[CF121E]Lucky Array

题目大意:有$n$个数$s_i$,两个操作:

1. $add\;l\;r\;d:$把区间$[l,r]$加上$d$(保证任何时刻$s_i\leqslant10^4$)
2. $count\;l\;r:$询问区间$[l,r]$中有多少个数是幸运数字(幸运数字的定义是只包含$4$和$7$两个数字)

题解:分块,发现$[0,10^4]$中只有$30$个幸运数字,按$\sqrt{30n}$分块,每个块内维护值域数组。

卡点:

C++ Code:

#include <cstdio>
const int NUM[30] = {4, 7, 44, 47, 74, 77, 444, 447, 474, 477, 744, 747, 774, 777, 4444, 4447, 4474, 4477, 4744, 4747, 4774, 4777, 7444, 7447, 7474, 7477, 7744, 7747, 7774, 7777};

#define maxn 100010
#define Blonum 110
const int Blo = 317 * 5;

int n, m, B;
int s[maxn], get[10010];
int L[Blonum], R[Blonum], bl[maxn], tg[Blonum], num[Blonum][maxn];


int main(){
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", s + i);
		bl[i] = i / Blo + 1;
		num[bl[i]][s[i]]++;
	}
	B = bl[n];
	for (int i = 1; i <= B; i++) {
		L[i] = (i - 1) * Blo;
		R[i] = i * Blo - 1;
	}
	L[1] = 1, R[B] = n;
	for (int i = 0; i < 30; i++) get[NUM[i]] = 1;
	while (m --> 0) {
		char op[10]; int l, r, d;
		scanf("%s%d%d", op, &l, &r);
		int lb = bl[l], rb = bl[r];
		if (*op == 'a') {
#define modify(x, y, z) num[x][y]--, num[x][y += z]++
			scanf("%d", &d);
			if (lb == rb) {
				for (int i = l; i <= r; i++) modify(lb, s[i], d);
			} else {
				for (int i = l; i <= R[lb]; i++) modify(lb, s[i], d);
				for (int i = lb + 1; i < rb; i++) tg[i] += d;
				for (int i = L[rb]; i <= r; i++) modify(rb, s[i], d);
			}
#undef modify
		} else {
			int res = 0;
			if (lb == rb) {
				for (int i = l; i <= r; i++) res += get[s[i] + tg[lb]];
			} else {
				for (int i = l; i <= R[lb]; i++) res += get[s[i] + tg[lb]];
				for (int i = lb + 1; i < rb; i++) {
					for (int j = 0; j < 30; j++) if (tg[i] <= NUM[j]) res += num[i][NUM[j] - tg[i]];
				}
				for (int i = L[rb]; i <= r; i++) res += get[s[i] + tg[rb]];
			}
			printf("%d\n", res);
		}
	}
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/Memory-of-winter/p/10084701.html
今日推荐