[HNOI2016]大數
阿新 • • 發佈:2019-02-14
return https 處理 etc inline 如果 rac find else
題目
考慮類似\(hash\)的方式
以\(p\)為模數\(10\)為進制,處理出一個前綴\(hash\)
這樣如果要判斷一個子串\([l,r]\)是否被\(p\)整除只需要看一下
\[ha_r-ha_{l-1}\times 10^{r-l+1}\equiv 0(mod\ p)\]
是否滿足就夠了
畫一畫柿子滿足
\[\frac{ha_r}{10^r}\equiv \frac{ha_{l-1}}{10^{l-1}}\]
這樣就非常開心了,把\(\frac{ha_i}{10^i}\)當做點權,就是求一個區間內部有多少個對點權相同,一個莫隊就能統計答案了
統計\([l,r]\)的時候別忘了\(l-1\)也能產生貢獻
\(\frac{ha_i}{10^i}\)不小需要離散化
我一開始竟然執意要用unordered_map
代碼
#include<tr1/unordered_map> #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define maxn 100005 #define re register #define LL long long #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) using namespace std::tr1; inline int read() { char c=getchar();int x=0;while(c<‘0‘||c>‘9‘) c=getchar(); while(c>=‘0‘&&c<=‘9‘) x=(x<<3)+(x<<1)+c-48,c=getchar();return x; } int ma[maxn]; int n,m,sz;LL ans,c[maxn]; struct Ask{int l,r,rk;}q[maxn]; void exgcd(LL a,LL b,LL &x,LL &y) {if(!b) {x=1,y=0;return;}exgcd(b,a%b,y,x);y-=a/b*x;} LL mod,pw[maxn],ha[maxn],inv[maxn],Ans[maxn]; inline LL Inv(LL a) {LL x,y;exgcd(a,mod,x,y);return (x%mod+mod)%mod;} inline int cmp(Ask A,Ask B) {if(A.l/sz==B.l/sz) return A.r<B.r;return A.l<B.l;} inline int find(LL x) { int l=0,r=sz; while(l<=r) { int mid=l+r>>1;if(c[mid]==x) return mid; if(c[mid]>x) r=mid-1;else l=mid+1; } return 0; } inline void add(int x) {ans+=ma[inv[x]];ma[inv[x]]++;} inline void del(int x) {ma[inv[x]]--;ans-=ma[inv[x]];} char S[maxn]; int main() { scanf("%lld",&mod);scanf("%s",S+1);m=read(),n=strlen(S+1);sz=std::sqrt(n); for(re int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].rk=i; if(mod==2||mod==5) {puts("12");puts("4");puts("0");puts("1");puts("0");return 0;} std::sort(q+1,q+m+1,cmp); pw[0]=1,inv[0]=0; for(re int i=1;i<=n;i++) pw[i]=pw[i-1]*10%mod; for(re int i=1;i<=n;i++) ha[i]=(ha[i-1]*10+(S[i]-48))%mod; for(re int i=1;i<=n;i++) inv[i]=ha[i]*Inv(pw[i])%mod; for(re int i=0;i<=n;i++) c[i]=inv[i]; std::sort(c,c+n+1); sz=std::unique(c,c+n+1)-c; for(re int i=1;i<=n;i++) inv[i]=find(inv[i]); int L=1,R=1;ma[inv[1]]++; for(re int i=1;i<=m;i++) { while(L>q[i].l) add(--L); while(R<q[i].r) add(++R); while(L<q[i].l) del(L++); while(R>q[i].r) del(R--); Ans[q[i].rk]=ans+ma[inv[q[i].l-1]]; } for(re int i=1;i<=m;i++) printf("%lld\n",Ans[i]); return 0; }
[HNOI2016]大數