正解:莫队
解题报告:
这题首先要发现一个结论,是这样儿的:
若p不是10的约数(即2和5) 时,当第i位到第n位组成的数%p==第j位到第n位组成的数%p,那么第i位到第j位上的数组成的数%p=0
试证如下:
记后缀数组num[i]:第i位到第n位构成的数,dat[i,j]:第i位到第j位构成的数
那么可以表示出dat[i,j-1]=(num[j]-num[i])*10j-i
因为现在已知num[i]=num[j]了,所以dat[i,j-1]=0
(显然指的是%p意义下昂QAQ
所以可以先预处理出后缀数组,于是问题就变成了这样:
有一些询问,每个询问给定一个区间,求区间内相同元素的数量
这不就是,莫队经典板子题了嘛,,,然后就做完了QAQ
然后以上都是我们在p不是10的约数的情况下讨论的(因为当p是10的约数时可能有更多QAQ
但是考虑到p是10的约数就只可能p=2或p=5嘛,然后2和5的倍数的性质又特别明显——尾数484倍数,所以直接前缀和就好辣QAQ
具体等下放代码QAQ
然后关于实现,并不很难和莫队普通题都差不多
唯一一个要注意的是这样儿的:
对于[l,r],因为计算的是[l,r]之间的数,所以实际上的那个num是要算到r+1的,但是同时要注意的是,r+1是不能计入数量的,而且在统计完答案之后还要把ans中的关于r+1多计算的减回来
但是想到这儿还要想到一个细节
就是当给定的r到达最右端的时候,如果依然按照上面的套路来会有问题,因为那样加上的会是0的数量,但是在离散化之后最小的数都是1
所以认真想想可以发现最右端的右边的贡献其实就是0的贡献,然后就想到怎么求0的离散化之后的值,显然在排序之后要么就是麻油0要么就是0离散化之后=1,分类讨论一下就好
表述不太清晰感觉,,,所以单独放一下这段的代码趴QAQ
(然后其实我好像做复杂了,,,因为我看到好像别人都麻油分类讨论什么的,,,直接一视同仁地做过去就欧克了,,,估计是前面有什么处理不一样,但是我jio得也就多打几句话而已,所以就懒得再修改了QAQ
if(r!=str_lth-)ret+=num[dat[r+]];else if(st[]==)ret+=num[];
as[ques[i].id]=ret;if(r!=str_lth-)ret-=num[dat[r+]];else if(st[]==)ret-=num[];
其实也就两句而已QAQ
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define rg register
#define gc getchar()
#define ll unsigned long long
#define ls(x) (x<<1)
#define rs(x) ((x<<1)|1)
#define rp(i,x,y) for(rg ll i=x;i<=y;++i)
#define my(i,x,y) for(rg ll i=x;i>=y;--i) const ll M=+,N=+;
ll p,m,str_lth,sq_lth,dat[N],st[N],tot,num[N],as[M],sum[N];
string str;
struct qs{ll l,r,id;}ques[M]; il ll read()
{
rg char ch=gc;rg ll x=;rg bool y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il bool cmp(qs gd,qs gs){return gd.r/sq_lth==gs.r/sq_lth?gd.l<gs.l:gd.r<gs.r;}
il void wk1()
{
string str;cin>>str;str=' '+str;str_lth=str.length();sq_lth=sqrt(str_lth);ll tmp=;
my(i,str_lth-,)st[i]=dat[i]=(dat[i+]+tmp*(str[i]^''))%p,tmp=tmp*%p;
sort(st+,st+str_lth+);tot=unique(st+,st+str_lth+)-st;rp(i,,str_lth-)dat[i]=lower_bound(st+,st+tot,dat[i])-st;
m=read();rp(i,,m)ques[i]=(qs){read(),read(),i};sort(ques+,ques++m,cmp);ll ret=,l=ques[].r+,r=ques[].r;
rp(i,,m)
{
while(l>ques[i].l)ret+=num[dat[--l]]++;
while(r<ques[i].r)ret+=num[dat[++r]]++;
while(l<ques[i].l)ret-=--num[dat[l++]];
while(r>ques[i].r)ret-=--num[dat[r--]];
if(r!=str_lth-)ret+=num[dat[r+]];else if(st[]==)ret+=num[];
as[ques[i].id]=ret;if(r!=str_lth-)ret-=num[dat[r+]];else if(st[]==)ret-=num[];
}
rp(i,,m)if(as[i])printf("%lld\n",as[i]);else printf("0\n");
}
il void wk2()
{
string str;cin>>str;str=' '+str;str_lth=str.length();m=read();rp(i,,m)ques[i]=(qs){read(),read(),i};
rp(i,,str_lth)dat[i]=(str[i]^'')%p,st[i]=st[i-]+(dat[i]==),sum[i]=sum[i-]+(dat[i]==)*i;
rp(i,,m)printf("%lld\n",sum[ques[i].r]-sum[ques[i].l-]-(ques[i].l-)*(st[ques[i].r]-st[ques[i].l-]));
} int main()
{
p=read();if(p!= && p!=)wk1();else wk2();
return ;
}
最后放下这个题目的代码!