[莫队] [小清新] 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]\)。止步于此。

观察这两个除数,前者显然是满足的。关于后者,这里分类讨论:

  1. \(\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\),离散化后莫队即可。

  2. 否则,\(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;
}

posted @ 2026-01-12 20:17  Zwi  阅读(2)  评论(0)    收藏  举报