luogu P3245 [HNOI2016]大數
阿新 • • 發佈:2021-07-10
題面傳送門
我們考慮設\(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]); }