「HNOI2016」大数
题意
做法
艹,这TM和莫队有个der的关系?????????
虽然总感觉他和莫队有关系,但是总想不到怎么做
事实上就是莫队
设数字为:\(\overline{a_1a_2a_3a_4a_5...a_n}\)
设\(t_i\)为\(\overline{a_ia_{i+1}a_{i+2}...a_{n}}\mod p\)的值。
这个\(t\)数组可以\(O(n)\)求出来。
再研究一下如果\(\overline{a_la_{l+1}...a_{r}}\)是\(p\)的倍数呢?那么不难发现\(t_{l}-t_{r+1}≡0 \mod p\),因为\(\overline{a_la_{l+1}...a_{r}}≡0\mod p,{a_la_{l+1}...a_{r}}*10^{n-r}≡0\mod p\),所以\(t_{l}≡t_{r+1}\)。
但是是不是\(t_{l}≡t_{r+1}\),那么\(\overline{a_la_{l+1}...a_{r}}≡0\mod p\),首先我们知道\({a_la_{l+1}...a_{r}}*10^{n-r}≡0\mod p\),如果\(gcd(10^{n-r},p)=1\),那么这个是绝对成立的,但是如果\(gcd(10^{n-r},p)≠1\),则不一定成立,此时\(p=2,5\),那么对于这两种情况,暴力判断如果这个位置能被整除,那么以这个位置作为\(r\)的区间一定能被整除。
对于\(p≠2,5\)的情况,就是维护\([l,r+1]\)区间中\(t\)数组的相等对数,直接莫队\(O(n\sqrt{n})\)暴力上就行了,别忘了\(t\)数组离散化哦。
时间复杂度:\(O(n\sqrt{n})\)。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 110000
using namespace std;
typedef long long LL;
char st[N];
LL a[N];
LL n,p,m;
LL f1[N];LL f2[N];//2或者5的情况
LL belong[N],block;//分块
LL si[N],id[N],be[N],cnt;//离散化
LL tot[N];
LL ans;//移动的ans
struct query
{
LL l,r,id;
}q[N];LL anslist[N];
inline bool cmp1(LL x,LL y){return si[x]<si[y];}
inline bool cmp2(query x,query y){return be[x.l]!=be[y.l]?x.l<y.l:x.r<y.r;}
inline void add(LL x){ans+=tot[x];tot[x]++;}
inline void del(LL x){tot[x]--;ans-=tot[x];}
int main()
{
scanf("%lld",&p);
scanf("%s",st+1);n=strlen(st+1);
for(LL i=1;i<=n;i++)a[i]=st[i]-'0';
if(p==2 || p==5)
{
for(LL i=1;i<=n;i++)
{
if(a[i]%p==0)f1[i]++,f2[i]+=i;
f1[i]+=f1[i-1],f2[i]+=f2[i-1];
}
scanf("%lld",&m);
for(LL i=1;i<=m;i++)
{
LL l,r;scanf("%lld%lld",&l,&r);
LL x1=f1[r]-f1[l-1];LL x2=f2[r]-f2[l-1];
printf("%lld\n",x2-(LL)x1*(l-1));
}
}
else
{
LL mo=1;
for(LL i=n;i>=1;i--)si[i]=(si[i+1]+mo*a[i])%p,mo=(mo*10)%p,id[i]=i;
si[++n]=0;id[n]=n;
sort(id+1,id+n+1,cmp1);
for(LL i=1;i<=n;i++)
{
if(i==1 || be[cnt]!=si[id[i]])cnt++,be[cnt]=si[id[i]];
si[id[i]]=cnt;
}
block=sqrt(n);
for(LL i=1;i<=n;i++)be[i]=(i-1)/block+1;
scanf("%lld",&m);
for(LL i=1;i<=m;i++){scanf("%lld%lld",&q[i].l,&q[i].r);q[i].id=i;}
sort(q+1,q+m+1,cmp2);
LL l=1,r=0;
for(LL i=1;i<=m;i++)
{
q[i].r++;
while(r<q[i].r)add(si[r+1]),r++;
while(l>q[i].l)add(si[l-1]),l--;
while(r>q[i].r)del(si[r]),r--;
while(l<q[i].l)del(si[l]),l++;
anslist[q[i].id]=ans;
}
for(LL i=1;i<=m;i++)printf("%lld\n",anslist[i]);
}
return 0;
}