Problem
Solution
我一看题:不会做
旁边的大佬一看题:(惊呼)这难道又是莫队?
Orz我果然还是太弱了
这个题目只需要将问题转化一下。
比如对于模数p=11,有字符串1213。我们用后缀和(因为字符串是倒着的啊)的思想,则有suf[4]=3,suf[1]=1213,而(suf[1]-suf[4])%11==0则表明字符串[1,3]是可以被11整除的。那么我们不妨对suf数组进行取模运算,我们可以得到类似的结论(suf[1]%11-suf[4]%11)%11==0则表明整除。
那么这个问题就变成了一个区间询问相同数对的对数的问题。也就是一道莫队的模板题。
另外,10并不是一个质数,所以当模数为2或5的时候,特判处理一下即可。比较容易处理,因为只需要尾数能被2或5整除那么就可以被2或5整除。所以它在第i位,以它结尾的整除的就有i个,然后前缀和一下,询问时再减去开头位置超过ql而导致不合法的个数(ql-1)*(cnt[qr]-cnt[ql-1])。
值得注意的是,因为在统计答案的时候r可能会超过n,比如之前的那个例子,要统计1213的答案时,需要判断(suf[1]%11-suf[5]%11)%11。所以读入之后,在字符串尾再加入一个’0’。
Code
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn=100010;
struct query{
int l,r,pos,id;
bool operator < (const query &x)const
{
if(pos==x.pos) return r<x.r;
return pos<x.pos;
}
}q[maxn];
int n,m,p,sqr,tot,l,r,suf[maxn],cnt[maxn],a[maxn],t[maxn];
ll tmp,ans[maxn];
char s[maxn];
template <typename Tp> inline void read(Tp &x)
{
x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
void work()
{
for(int i=1;i<=n;i++)
if((s[i]-'0')%p==0)
cnt[i]=1,suf[i]=i;
for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1],suf[i]+=suf[i-1];
for(int i=1,ql,qr;i<=m;i++)
{
read(ql);read(qr);
printf("%lld\n",(ll)suf[qr]-suf[ql-1]-(ll)(ql-1)*(cnt[qr]-cnt[ql-1]));
}
}
int input()
{
read(p);scanf("%s",s+1);read(m);
n=strlen(s+1);sqr=(int)sqrt(n);
if(p==2||p==5){work();return 0;}
s[++n]='0';
for(int i=1;i<=m;i++)
{
read(q[i].l);read(q[i].r);++q[i].r;
q[i].pos=(q[i].l-1)/sqr+1;q[i].id=i;
}
sort(q+1,q+m+1);
ll fac=1;
for(int i=n;i>=1;i--)
{
suf[i]=((ll)(s[i]-'0')*fac%p+suf[i+1])%p;
a[i]=suf[i];
fac=fac*10%p;
}
sort(a+1,a+n+1);
tot=unique(a+1,a+n+1)-a-1;
for(int i=1;i<=n;i++) suf[i]=lower_bound(a+1,a+tot+1,suf[i])-a;
return 1;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
if(!input()) return 0;
l=1;r=0;tmp=0;
for(int i=1;i<=m;i++)
{
while(r<q[i].r) tmp+=t[suf[++r]],t[suf[r]]++;
while(l>q[i].l) tmp+=t[suf[--l]],t[suf[l]]++;
while(r>q[i].r) t[suf[r]]--,tmp-=t[suf[r--]];
while(l<q[i].l) t[suf[l]]--,tmp-=t[suf[l++]];
ans[q[i].id]=tmp;
}
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}