luogu P3245 [HNOI2016]大數
阿新 • • 發佈:2019-04-05
優秀 否則 lld += pan con b- ret efi
傳送門
\(HNOI2019\)前最後一題了qwq
這題要分情況,如果\(p=2\)或\(5\),那麽只要區間內最後一個數字是\(p\)的倍數就好了,這個可以莫隊,也有更優秀的做法.莫隊做法可以看代碼懶
否則,考慮一個數怎麽表示,記\(s_i\)為前\(i\)為構成的數,可以知道區間\([i,j]\)的數應該是\(s_r-s_{l-1}*10^{r-l+1}\),現在要求這個數模\(p\)為0,那麽也就是\[s_r-s_{l-1}*10^{r-l+1}\equiv0\ (\mathrm{mod}\ p)\]
兩邊同時除掉\(10^r\),得到
\[s_r*10^{-r}-s_{l-1}*10^{-(l-1)}\equiv0\ (\mathrm{mod}\ p)\]
如果位置\(i\)的權值為\(s_i*10^{-i}\),那麽一個區間\([i,j]\)的答案就是\([i-1,j]\)中每種權值相同的點對個數,這個還是比較好寫的
#include<bits/stdc++.h> #define LL long long #define db long double #define il inline using namespace std; const int N=1e5+10; il LL rd() { LL x=0,w=1;char ch=0; while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*w; } int p,a[N],n,sqt,q,be[N]; LL an[N],na; char cc[N]; struct qu { int l,r,i; bool operator < (const qu &bb) const {return be[l]!=be[bb.l]?l<bb.l:r<bb.r;} }qq[N]; int fpow(int a,int b){a%=p;int an=1;while(b){if(b&1) an=1ll*an*a%p;a=1ll*a*a%p,b>>=1;} return an;} namespace ct1 { int cn; void wk() { sort(qq+1,qq+q+1); for(int i=1,l=1,r=0;i<=q;++i) { while(r<qq[i].r) ++r,cn+=a[r]%p==0,na+=(a[r]%p==0?r-l+1:0); while(r>qq[i].r) na-=(a[r]%p==0?r-l+1:0),cn-=a[r]%p==0,--r; while(l<qq[i].l) na-=cn,cn-=a[l]%p==0,++l; while(l>qq[i].l) --l,cn+=a[l]%p==0,na+=cn; an[qq[i].i]=na; } } } namespace ct2 { int cn[N],b[N],m; void wk() { int pp=fpow(10,p-2); b[++m]=0; for(int i=1,j=1,sm=0;i<=n;++i) { sm=1ll*sm*10%p+a[i],j=1ll*j*pp%p; a[i]=1ll*sm*j%p; b[++m]=a[i]; } sort(b+1,b+m+1),m=unique(b+1,b+m+1)-b-1; for(int i=0;i<=n;++i) a[i]=lower_bound(b+1,b+m+1,a[i])-b; for(int i=1;i<=q;++i) --qq[i].l; sort(qq+1,qq+q+1); for(int i=1,l=0,r=-1;i<=q;++i) { while(r<qq[i].r) ++r,++cn[a[r]],na+=cn[a[r]]-1; while(r>qq[i].r) na-=cn[a[r]]-1,--cn[a[r]],--r; while(l<qq[i].l) na-=cn[a[l]]-1,--cn[a[l]],++l; while(l>qq[i].l) --l,++cn[a[l]],na+=cn[a[l]]-1; an[qq[i].i]=na; } } } int main() { p=rd(); scanf("%s",cc+1); n=strlen(cc+1); sqt=sqrt(n); for(int i=1;i<=n;++i) a[i]=cc[i]-'0',be[i]=i/sqt; q=rd(); for(int i=1;i<=q;++i) qq[i].l=rd(),qq[i].r=rd(),qq[i].i=i; if(p==2||p==5) ct1::wk(); else ct2::wk(); for(int i=1;i<=q;++i) printf("%lld\n",an[i]); return 0; }
luogu P3245 [HNOI2016]大數