BZOJ 4542 大数 发表于 2017-03-24 | 更新于 2018-06-18 LinkSolution 如果上式==0==0==0,那么可以得到 也==0==0==0。 这样的话当 的时候,反推,用后缀的差是否为零来判断s[l:r]s[l:r]s[l:r]是否 剩下的特殊处理就好了 Code123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778#include "lucida"using std::sort;using std::unique;using std::lower_bound;const int MAXN=100000+11;int n,bn[MAXN],m;int64 Ans[MAXN],P;char S[MAXN]; struct Opt { int l,r,id; bool operator <(const Opt &x) const { return bn[l]!=bn[x.l]?bn[l]<bn[x.l]:r<x.r; }}p[MAXN];namespace Mo { int64 cAns; int cnt[MAXN],c[MAXN]; int64 suf[MAXN],nums[MAXN]; int64 C2(int n) { return n<2?0:(int64)n*(n-1)>>1; } void Modify(int pos,int d) { cAns-=C2(cnt[c[pos]]); cnt[c[pos]]+=d; cAns+=C2(cnt[c[pos]]); } void Solve() { int bsz=sqrt(n+0.5); for(int i=1;i<=n;++i) bn[i]=(i-1)/bsz+1; int nc=0; for(int i=n,pw=1;i;--i,pw=(int64)pw*10%P) { suf[i]=((int64)(S[i]-'0')*pw+suf[i+1])%P; nums[++nc]=suf[i]; } nums[++nc]=0;sort(nums+1,nums+1+nc); nc=unique(nums+1,nums+1+nc)-nums-1; for(int i=1;i<=n+1;++i) c[i]=lower_bound(nums+1,nums+1+nc,suf[i])-nums; sort(p+1,p+1+m); for(int i=1;i<=m;++i) ++p[i].r; //区间内有多少种同颜色的点 for(int i=p[1].l;i<=p[1].r;++i) Modify(i,1); Ans[p[1].id]=cAns; for(int i=2;i<=m;++i) { for(int t=p[i-1].l-1;t>=p[i].l;--t) Modify(t,1); for(int t=p[i-1].r+1;t<=p[i].r;++t) Modify(t,1); for(int t=p[i-1].l;t<=p[i].l-1;++t) Modify(t,-1); for(int t=p[i-1].r;t>=p[i].r+1;--t) Modify(t,-1); Ans[p[i].id]=cAns; } }}namespace Sp { int cnt[MAXN]; int64 sum[MAXN]; void Solve() { for(int i=1;i<=n;++i) { cnt[i]=cnt[i-1]+((S[i]-'0')%P==0); sum[i]=sum[i-1]+((S[i]-'0')%P==0)*i;//(i-1)?? } for(int i=1;i<=m;++i) Ans[i]=(sum[p[i].r]-sum[p[i].l-1])-(int64)(cnt[p[i].r]-cnt[p[i].l-1])*(p[i].l-1); }}int main() { freopen("input","r",stdin); is>>P>>(S+1)>>m;n=strlen(S+1); for(int i=1;i<=m;++i) { is>>p[i].l>>p[i].r; p[i].id=i; } if(10%P) Mo::Solve(); else Sp::Solve(); for(int i=1;i<=m;++i) os<<Ans[i]<<'\n'; return 0;}