[莫队] [小清新] P3245 [HNOI2016] 大数
posted on 2024-04-19 15:08:30 | under | source
难得的莫队好题。
首先将 \(S[l,r]\) 拆成 \(\frac{S[l,n]-S[r+1,n]}{10^{n-r}}\)。
然后判定 \(p\mid S[l,r]\) 变成了 \(10^{n-r}*p\mid S[l,n]-S[r+1,n]\)。止步于此。
观察这两个除数,前者显然是满足的。关于后者,这里分类讨论:
-
\(\gcd(10^{n-r},p)\ne 1\):则两个除数互不干扰,即满足 \(p\mid S[l,n]-S[r+1,n]\) 即可。变一下就是 \(S[l,n] \bmod p - S[r+1,n]\bmod p\),离散化后莫队即可。
-
否则,\(p=2,5\) 之一:根据小奥,等价于 \(p\mid S_r\),直接前缀和处理即可。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 5;
int p, n, m, l, r, s[N], b[N], ans[N], res, idw[N], cnt[N][10], cnt2[N][10], len, buc[N];
char c[N];
struct ask{int l, r, id;} q[N];
inline bool cmp(ask A, ask B) {return b[A.l] == b[B.l] ? A.r < B.r : b[A.l] < b[B.l];}
inline void Idw(){
int idw[N];
for(int i = 1; i <= n + 1; ++i) idw[i] = s[i];
sort(idw + 1, idw + 2 + n); int _n = unique(idw + 1, idw + 2 + n) - idw - 1;
for(int i = 1; i <= n + 1; ++i) s[i] = lower_bound(idw + 1, idw + 1 + _n, s[i]) - idw;
}
inline void add(int p) {res += buc[p], ++buc[p];}
inline void del(int p) {--buc[p], res -= buc[p];}
signed main(){
scanf("%lld%s", &p, c + 1), n = strlen(c + 1);
for(int i = n, pw = 1; i; --i, pw = pw * 10 % p) s[i] = (s[i + 1] + pw * (c[i] - '0') % p) % p;
scanf("%lld", &m);
for(int i = 1; i <= m; ++i) scanf("%lld%lld", &q[i].l, &q[i].r), q[i].id = i;
if(p == 2 || p == 5){
for(int i = 1; i <= n; ++i)
for(int j = 0; j < 10; ++j)
cnt[i][j] = cnt[i - 1][j] + ((c[i] - '0') == j), cnt2[i][j] = cnt2[i - 1][j] + i * ((c[i] - '0') == j);
for(int i = 1; i <= m; ++i)
for(int j = 0; j < 10; ++j)
if(j % p == 0) ans[i] += cnt2[q[i].r][j] - cnt2[q[i].l - 1][j] - (q[i].l - 1) * (cnt[q[i].r][j] - cnt[q[i].l - 1][j]);
}
else{
len = ceil(1.0 * (n + 1) / sqrt(m));
for(int i = 1; i <= n + 1; ++i) b[i] = (i + len - 1) / len;
for(int i = 1; i <= m; ++i) ++q[i].r;
Idw(), sort(q + 1, q + 1 + m, cmp);
l = 1, r = 0, res = 0;
for(int i = 1; i <= m; ++i){
while(r < q[i].r) add(s[++r]);
while(l > q[i].l) add(s[--l]);
while(r > q[i].r) del(s[r--]);
while(l < q[i].l) del(s[l++]);
ans[q[i].id] = res;
}
}
for(int i = 1; i <= m; ++i) printf("%lld\n", ans[i]);
return 0;
}

浙公网安备 33010602011771号