题目大意:有$n$个数$s_i$,两个操作:
1. $add;l;r;d:$把区间$[l,r]$加上$d$(保证任何时刻$s_ileqslant10^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 ", res); } } return 0; }