版权声明:_ https://blog.csdn.net/lunch__/article/details/84875340
题意
- 给你一个由数字构成的字符串,每次询问一个区间内有多少个子区间满足子区间构成的数是 的倍数。
这个题好像并没有那么裸,就有一个性质需要观察,当 且 的时候,令 为以 开始的后缀,那么只要 ,区间 构成的数是 的倍数。令区间 构成的数为 ,我们可以发现这样一个等式 ,当 时,又因为 ,所以 ,得出来这个之后就是一个莫队统计区间颜色个数的模板题了.
或 的情况计算比较容易,这里就不详细讲了
Codes
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 10;
char S[N];
ll ans[N], c[N], res;
int mod, q, n, size, cnt;
int be[N], f[N], pow10[N], tmp[N];
struct Que {
int x, y, id;
bool operator < (const Que &T) const {
if (be[x] == be[T.x]) return y < T.y;
return be[x] < be[T.x];
}
}Q[N];
void update(int x, int y) {
res -= (c[x] - 1) * c[x] / 2;
c[x] += y;
res += (c[x] - 1) * c[x] / 2;
}
int main() {
#ifdef ylsakioi
freopen("2053.in", "r", stdin);
freopen("2053.out", "w", stdout);
#endif
scanf("%d%s%d", &mod, S + 1, &q);
n = strlen(S + 1), size = sqrt(n);
for (int i = 1; i <= q; ++ i) {
scanf("%d%d", &Q[i].x, &Q[i].y), ++ Q[i].y;
be[Q[i].x] = Q[i].x / size, Q[i].id = i;
}
sort(Q + 1, Q + q + 1);
if (mod == 2 || mod == 5) {
for (int i = 1; i <= n; ++ i) {
int flag = (S[i] ^ '0') % mod == 0;
f[i] = f[i - 1] + i * flag;
c[i] = c[i - 1] + flag;
}
for (int i = 1; i <= q && (-- Q[i].y); ++ i)
ans[Q[i].id] = (f[Q[i].y] - f[Q[i].x - 1]) - (c[Q[i].y] - c[Q[i].x - 1]) * (Q[i].x - 1);
}
else {
ll now = 1; tmp[cnt = 1] = 0;
for (int i = n; i >= 1; -- i, (now *= 10) %= mod)
tmp[++ cnt] = f[i] = (now * (S[i] ^ '0') + f[i + 1]) % mod;
sort(tmp + 1, tmp + cnt + 1);
cnt = unique(tmp + 1, tmp + cnt + 1) - tmp - 1;
for (int i = 1; i <= n + 1; ++ i)
f[i] = lower_bound(tmp + 1, tmp + cnt + 1, f[i]) - tmp;
int l = 1, r = 0;
for (int i = 1; i <= q; ++ i) {
while (r < Q[i].y) update(f[++ r], 1);
while (r > Q[i].y) update(f[r --], -1);
while (l > Q[i].x) update(f[-- l], 1);
while (l < Q[i].x) update(f[l ++], -1);
ans[Q[i].id] = res;
}
}
for (int i = 1; i <= q; ++ i)
printf("%lld\n", ans[i]);
return 0;
}