(以下用[l,r]表示[l,r]这一段数字)对每一个后缀[i,n],求出这一段数对p取模后的值。那么对于某一段区间[l,r],如果满足[l,n]和[r+1,n]的值相同,那么显然有[l,r] mod p=10,实际上,是[l,r]*10^(n-r) mod p=0。那么离散化之后用莫队维护一下就好了。
注意到当p=2或p=5的时候并不一定满足。因此需要特判。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define N 100005 #define ll long long using namespace std; int n,m,cnt,a[N],c[N],blg[N],num[N]; ll p,ans,ot[N]; struct node{ ll x; int y; }s[N]; struct q_node{ int l,r,id; }b[N]; int read(){ int x=0; char ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x; } void work(){ int i,x,y; for (i=1; i<=n; i++){ s[i]=s[i-1]; if (!(a[i]%p)){ s[i].x+=i; s[i].y++; } } m=read(); while (m--){ x=read(); y=read(); printf("%lld\n",s[y].x-s[x-1].x-(ll)(x-1)*(s[y].y-s[x-1].y)); } } bool cmp1(const node &u,const node &v){ return u.x<v.x; } bool cmp2(const q_node &u,const q_node &v){ return blg[u.l]<blg[v.l] || blg[u.l]==blg[v.l] && u.r<v.r; } void mdy(int x,int y){ if (y>0){ ans+=num[c[x]]; num[c[x]]++;} else{ num[c[x]]--; ans-=num[c[x]]; } } int main(){ scanf("%lld",&p); int i; char ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); for (; ch>='0' && ch<='9'; ch=getchar()) a[++n]=ch-'0'; if (p==2 || p==5){ work(); return 0; } ll now=1; for (i=n; i; i--,now=now*10%p){ s[i].x=(s[i+1].x+a[i]*now)%p; s[i].y=i; } s[++n].x=0; s[n].y=n; sort(s+1,s+n+1,cmp1); for (i=1; i<=n; i++){ if (i==1 || s[i].x!=s[i-1].x) cnt++; c[s[i].y]=cnt; } m=read(); for (i=1; i<=m; i++){ b[i].l=read(); b[i].r=read()+1; b[i].id=i; } int sz=(int)sqrt(n)+1; for (i=1; i<=n; i++) blg[i]=(i-1)/sz; sort(b+1,b+m+1,cmp2); int l=1,r=1; num[c[1]]++; for (i=1; i<=m; i++){ while (l<b[i].l) mdy(l++,-1); while (l>b[i].l) mdy(--l,1); while (r<b[i].r) mdy(++r,1); while (r>b[i].r) mdy(r--,-1); ot[b[i].id]=ans; } for (i=1; i<=m; i++) printf("%lld\n",ot[i]); return 0; }
by lych
2016.4.22