题目大意:有$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;
}
来源:oschina
链接:https://my.oschina.net/u/4270193/blog/3720873