题解:http://www.cnblogs.com/Ngshily/p/5409409.html
如何判断一个炒鸡大的数 n n能不能被另一个数 P P整除,,,我们有如下结论若 xmodP=a xmodP=a,且 (n∗10k+x)modP=a (n∗10k+x)modP=a, k k为 x x的长度, gcd(P,10k)=1 gcd(P,10k)=1那么 nmodP=0 nmodP=0
胡乱证明分割线**********
因为 (n∗10k+x)modP=((n∗10k)modP+xmodP)modP=a (n∗10k+x)modP=((n∗10k)modP+xmodP)modP=a,且 xmodP=a xmodP=a,则 (n∗10k)modP=0 (n∗10k)modP=0
当且仅当 10kmodP 10kmodP不为 0 0时 nmodP=0 nmodP=0
当满足这个条件时,我们把 x x看作序列的后缀 P P,问题就转化为求区间 [l,r+1] [l,r+1]中,有多少对 a a相同,,,莫队again
由于 P P是质数,,,所以需要特判的只有 2 2和 5 5
所谓的特判就是数一哈有几个偶数,几个 0 0或 5 5什么的,,,
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } return *p1++; } inline void read(int &x){ char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } inline int read(int *s){ char c=nc(); int len=0; for (;!(c>='0' && c<='9');c=nc()); for (;c>='0' && c<='9';s[++len]=c-'0',c=nc()); return len; } const int N=100005; struct event{ int l,r,lpos; int idx; bool operator < (const event &B) const{ return lpos==B.lpos?r<B.r:lpos<B.lpos; } }eve[N]; int tot; int n,m,B,P; int S[N]; ll sa[N],Ans[N]; ll sx[N],icnt; inline int Bin(ll x){ return lower_bound(sx+1,sx+icnt+1,x)-sx; } namespace Work{ ll ans; ll num[N]; inline void modify(int f,int x) { int pos=sa[x]; if (f==1) { ans-=num[pos]*(num[pos]-1)/2; num[pos]++; ans+=num[pos]*(num[pos]-1)/2; } else { ans-=num[pos]*(num[pos]-1)/2; num[pos]--; ans+=num[pos]*(num[pos]-1)/2; } } inline void Solve(){ int l=1,r=0; for (int i=1;i<=tot;i++) { eve[i].r++; while (r<eve[i].r) modify(1,++r); while (r>eve[i].r) modify(-1,r--); while (l<eve[i].l) modify(-1,l++); while (l>eve[i].l) modify(1,--l); Ans[eve[i].idx]=ans; } } } namespace Work25{ ll ans,cnt; inline void Solve(int k){ int l=1,r=0; for (int i=1;i<=tot;i++) { while (r<eve[i].r) { ++r; if (S[r]%k==0) cnt++,ans+=r-l+1; } while (r>eve[i].r) { if (S[r]%k==0) cnt--,ans-=r-l+1; r--; } while (l<eve[i].l) { ans-=cnt; if (S[l]%k==0) cnt--; l++; } while (l>eve[i].l) { --l; if (S[l]%k==0) cnt++; ans+=cnt; } Ans[eve[i].idx]=ans; } } } int main() { freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(P); n=read(S); S[++n]=0; sa[n]=1; for (int i=n-1;i;i--) sa[i]=sa[i+1]*10%P; sa[n]=sa[n]*S[n]; for (int i=n-1;i;i--) sa[i]=(sa[i]*S[i]%P+sa[i+1])%P; for (int i=1;i<=n;i++) sx[++icnt]=sa[i]; sort(sx+1,sx+icnt+1); icnt=unique(sx+1,sx+icnt+1)-sx-1; for (int i=1;i<=n;i++) sa[i]=Bin(sa[i]); B=sqrt(n); read(tot); for (int i=1;i<=tot;i++) { read(eve[i].l); read(eve[i].r); eve[i].lpos=(eve[i].l-1)/B+1; eve[i].idx=i; } sort(eve+1,eve+tot+1); if (P==2) Work25::Solve(2); else if (P==5) Work25::Solve(5); else Work::Solve(); for (int i=1;i<=tot;i++) printf("%lld\n",Ans[i]); return 0; }