[bzoj4542][Hnoi2016]大數——同餘+莫隊
阿新 • • 發佈:2018-12-05
題目大意:
給定一個質數p和一串數字序列,每次詢問一個區間[L,R]中有多少個子區間表示的數為p的倍數。
思路:
首先考慮如何判斷一段數字是不是p的倍數,不難想到可以用模p意義下的值來判斷,但是這樣最多便有可能會有\(n^2\)個餘數,每一次計算也需要區間長度的時間,不太方便。
考慮記錄以每一個點為起點的字尾所表示的數字在模p下的結果\(sum_i\),對於任意一段區間[L,R],不難發現\(sum_l-sum_{r+1}\)所表示的是[L,R]所表示的數\(\times 10^x\),對於素數裡面只有2,5是有可能整除後面的\(10^x\),於是我們只需要對2,5特殊判斷一下,其他的素數直接用\(sum_l-sum_{r+1}\)
這樣對於任意一個區間[L,R],我們只需要看\(sum_l\)和\(sum_{r+1}\)是否相同,題目便轉化為了數一個區間內的相同顏色的個數並求其貢獻,這種模型直接用莫隊維護即可。
#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i) #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i) #define MREP(i,x) for(int i=beg[x],v;v=to[i],i;i=las[i]) #define debug(x) cout<<#x<<"="<<x<<endl #define fi first #define se second #define mk make_pair #define pb push_back typedef long long ll; using namespace std; void File(){ freopen("bzoj4542.in","r",stdin); freopen("bzoj4542.out","w",stdout); } template<typename T>void read(T &_){ T __=0,mul=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')mul=-1; ch=getchar(); } while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar(); _=__*mul; } const int maxn=1e5+10; int n,p,m,a[maxn]; char str[maxn]; namespace subtask1{ ll s1[maxn],s2[maxn]; void work(){ REP(i,1,n){ s1[i]+=s1[i-1]; s2[i]+=s2[i-1]; if(a[i]%p==0){ ++s1[i]; s2[i]+=i; } } int l,r; REP(i,1,m){ read(l),read(r); printf("%lld\n",s2[r]-s2[l-1]-(s1[r]-s1[l-1])*(l-1)); } } } namespace subtask2{ int tot,bel[maxn]; ll sum[maxn],p10[maxn],b[maxn],ans[maxn],ton[maxn],now; struct Query{ int l,r,id; bool operator < (const Query & tt) const { if(bel[l]==bel[tt.l])return r<tt.r; return bel[l]<bel[tt.l]; } }qu[maxn]; void calc(int pos,int ty){ int w=sum[pos]; now-=ton[w]*(ton[w]-1)/2; ton[w]+=ty; now+=ton[w]*(ton[w]-1)/2; } void work(){ p10[0]=1; REP(i,1,n)p10[i]=p10[i-1]*10%p; ll ss=0; DREP(i,n,1){ ss=(ss+a[i]*p10[n-i])%p; sum[i]=(ss+p)%p; } REP(i,1,n+1)b[++tot]=sum[i]; sort(b+1,b+tot+1); tot=unique(b+1,b+tot+1)-b-1; REP(i,1,n+1)sum[i]=lower_bound(b+1,b+tot+1,sum[i])-b; REP(i,1,n)bel[i]=(i-1)/400+1; REP(i,1,m)read(qu[i].l),read(qu[i].r),qu[i].id=i; sort(qu+1,qu+m+1); int L=1,R=0; REP(i,1,m){ int l=qu[i].l,r=qu[i].r; while(L>l)calc(L-1,1),--L; while(R<r+1)calc(R+1,1),++R; while(L<l)calc(L,-1),++L; while(R>r+1)calc(R,-1),--R; ans[qu[i].id]=now; } REP(i,1,m)printf("%lld\n",ans[i]); } } int main(){ File(); read(p); scanf("%s",str+1); n=strlen(str+1); REP(i,1,n)a[i]=str[i]^'0'; read(m); if(p==2 || p==5)return subtask1::work(),0; else return subtask2::work(),0; return 0; }