小 B 有一个很大的数 S,长度达到了 N 位;这个数可以看成是一个串,它可能有前导 0,例如00009312345
。小B还有一个素数P。现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也
是P 的倍数)。例如 S为0077时,其子串 007有6个子串:0,0,7,00,07,007;显然0077的子串007有6个子串都是素
数7的倍数。
小 B 有一个很大的数 S,长度达到了 N 位;这个数可以看成是一个串,它可能有前导 0,例如00009312345
。小B还有一个素数P。现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也
是P 的倍数)。例如 S为0077时,其子串 007有6个子串:0,0,7,00,07,007;显然0077的子串007有6个子串都是素
数7的倍数。
第一行一个整数:P。第二行一个串:S。第三行一个整数:M。接下来M行,每行两个整数 fr,to,表示对S 的
子串S[fr…to]的一次询问。注意:S的最左端的数字的位置序号为 1;例如S为213567,则S[1]为 2,S[1…3]为 2
13。N,M<=100000,P为素数
输出M行,每行一个整数,第 i行是第 i个询问的答案。
2016.4.19新加数据一组
莫队算法
首先有一个性质:如果A*10^k+B=B(mod p),且p和10^k互质,则A%p=0。
那么,要判断一个s[l...r]是否是p的倍数,只要判断s[l...n]和s[r+1...n]在模n的意义下是否相等。
于是,我们可以预处理出每一个后缀s[i...n]对p取模的结果a[i]。然后对于一个询问[l,r],就转化成了询问[l,r+1]中有多少对相同的a[i]。用莫队算法就可以解决了。
当然p如果和10^k不互质,即p=2或p=5的时候要特殊考虑。
(具体实现方法见代码)
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<map> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 100010 using namespace std; int n,m,block,l,r; ll p,cnt[maxn],sum[maxn],ans[maxn],f[maxn],g[maxn]; char s[maxn]; struct data{int l,r,id,num;}q[maxn]; map<ll,ll> mp; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline bool cmp(data a,data b) { return a.num==b.num?a.r<b.r:a.num<b.num; } inline void solve() { F(i,1,n) { cnt[i]=cnt[i-1];sum[i]=sum[i-1]; if ((s[i]-'0')%p==0) cnt[i]++,sum[i]+=i; } m=read(); F(i,1,m) { int l=read(),r=read(); printf("%lld\n",sum[r]-sum[l-1]-(cnt[r]-cnt[l-1])*(l-1)); } } int main() { scanf("%lld%s",&p,s+1); n=strlen(s+1); if (p==2||p==5) { solve(); return 0; } block=(int)sqrt(n); m=read(); F(i,1,m) { q[i].l=read();q[i].r=read()+1; q[i].id=i;q[i].num=(q[i].l-1)/block+1; } sort(q+1,q+m+1,cmp); ll tmp=1; D(i,n,1) { f[i]=(f[i+1]+tmp*(s[i]-'0')%p)%p; tmp=tmp*10%p; } n++; F(i,1,n) g[i]=f[i]; sort(g+1,g+n+1); tmp=0; F(i,1,n) if (i==1||g[i]!=g[i-1]) mp[g[i]]=++tmp; F(i,1,n) f[i]=mp[f[i]]; F(i,1,m) { if (q[i].num!=q[i-1].num) { l=1;r=0;tmp=0; memset(cnt,0,sizeof(cnt)); } while (r<q[i].r){r++;tmp+=cnt[f[r]];cnt[f[r]]++;} while (l<q[i].l){cnt[f[l]]--;tmp-=cnt[f[l]];l++;} while (l>q[i].l){l--;tmp+=cnt[f[l]];cnt[f[l]]++;} ans[q[i].id]=tmp; } F(i,1,m) printf("%lld\n",ans[i]); return 0; }