luogu P3245 [HNOI2016]大数
题面传送门
我们考虑设\(Sum_i\)表示\([1,i]\)组成的数。
然后就是让求\(Sum_r-Sum_l\times 10^{r-l}=0\)
移项得到\(Sum_r=Sum_l\times 10^{r-l}\)
两边同乘\(10^l\)得到\(Sum_r\times 10^l=Sum_l\times 10^r\)
然后移项得到\(\frac{Sum_r}{10^r}=\frac{Sum_l}{10^l}\)
这个东西显然莫队统计。
但是如果你\(p=2|5\)就不能做。
观察,这两尾数都有性质,所以直接特判即可。
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 200000
#define M 30
#define mod 1000000007
#define eps (1e-7)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,m,k,l,r,p,F[N+5],A[N+5],cnt;ll po=1,Ans[N+5],tot,Sum[N+5],Q[N+5];char s[N+5];map<int,int> H;
struct ques{int l,r,id;}G[N+5],tmp;
I ll mpow(ll x,int y=p-2){ll ans=1;while(y) (y&1)&&(ans=ans*x%p),x=x*x%p,y>>=1;return ans;}
I bool cmp(ques x,ques y){return (x.l/k==y.l/k)?((x.l/k)&1?x.r<y.r:x.r>y.r):x.l<y.l;}
I void Make(int &x){!H[x]&&(H[x]=++cnt);x=H[x];}
I void Solve(){
re int i;for(i=1;i<=n;i++) A[i]=s[i]-'0',Sum[i]=Sum[i-1]+(!(A[i]%p))*i,Q[i]=Q[i-1]+(!(A[i]%p));
while(m--) scanf("%d%d",&l,&r),printf("%lld\n",Sum[r]-Sum[l-1]-(Q[r]-Q[l-1])*(l-1));exit(0);
}
int main(){
freopen("1.in","r",stdin);freopen("1.out","w",stdout);
re int i,j;scanf("%d%s",&p,s+1);n=strlen(s+1);scanf("%d",&m);if(p==2||p==5) Solve();k=n/sqrt(m);for(i=1;i<=n;i++) A[i]=(1ll*A[i-1]*10+s[i]-48)%p;k=ceil(n/sqrt(m));
for(i=1;i<=n;i++)po=po*10%p,A[i]=A[i]*mpow(po)%p;for(i=0;i<=n;i++) Make(A[i]);
for(i=1;i<=m;i++)scanf("%d%d",&G[i].l,&G[i].r),G[i].l--,G[i].id=i;sort(G+1,G+m+1,cmp);l=0;r=-1;for(i=1;i<=m;i++){
tmp=G[i];while(l>tmp.l) tot+=(F[A[--l]]++)*2+1;while(l<tmp.l) tot-=(--F[A[l++]])*2+1;
while(r<tmp.r) tot+=(F[A[++r]]++)*2+1;while(r>tmp.r) tot-=(--F[A[r--]])*2+1;Ans[tmp.id]=(tot-(tmp.r-tmp.l+1))/2;
}for(i=1;i<=m;i++) printf("%lld\n",Ans[i]);
}