您的位置:首页 > 其它

Bzoj4542--Hnoi2016大数

2016-10-25 10:01 423 查看

一开始想到过用莫队,没有想出来怎么去转移。。。

事实上对于一个子串是p的倍数的串有一个性质,就是开头和结尾的后缀串的余数相同,这个还是好理解的。

假设一个子串[l,r]数值为t,设t=xp,这个子串结尾对应的原串后缀[r+1,n]数值为t',设t'=y*p+r

那么这个串开头对应原串的后缀[l,n]值为w=t*10^(n-r+1)+t'=(x*10^(n-r+1)+y)*p+r,显然w%p=r

但是对于10的两个质因子2,5是不成立的,因为t*10^(n-r+1)%P=0

那么我们对于2和5单独来处理,2,5的话就只要结尾是2,5的倍数的都可以就可以简单求解了

代码: 

#include<bits/stdc++.h>
#define LL long long
using namespace std;

inline int read() {
int ret=0,f=1;char c=getchar();
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c<='9'&&c>='0') {ret=ret*10+c-'0';c=getchar();}
return ret*f;
}

#define MAXN 100005
#define MAXM 100005

int P,n,m,bl[MAXN],qsz,hs[MAXN];
char s[MAXN];LL te[MAXN],re[MAXN];
struct que{
int l,r,id;
}q[MAXM];LL ans[MAXM];

inline bool cmp(const que &a,const que &b) {
return bl[a.l]==bl[b.l]?a.r<b.r:a.l<b.l;
}

int BS(int v) {
int l=0,r=n,mid,ret;
while(l<=r) {
mid=l+r>>1;
if(hs[mid]>=v) r=mid-1,ret=mid;
else l=mid+1;
}
return ret;
}

int nl=1,nr=0,ap[MAXN];LL now;
inline void Chg(int v,int p) {
ap[v]+=p;now+=p>0?ap[v]-1:-ap[v];
}

int main() {
P=read();
scanf("%s",s+1);te[0]=1;
n=strlen(s+1);qsz=sqrt(n);
for(int i=1;i<=n;i++) bl[i]=i/qsz,te[i]=te[i-1]*10%P;
m=read();
for(int i=1;i<=m;i++) {
q[i].l=read();q[i].r=read();
q[i].id=i;
}
if(10%P) {
sort(q+1,q+m+1,cmp);
for(int i=n;i>0;i--) re[i]=(re[i+1]+(s[i]-'0')*te[n-i])%P,hs[i]=re[i];
sort(hs+1,hs+1+n);
for(int i=n;i>0;i--) re[i]=BS(re[i]);
for(int i=1;i<=m;i++) {
q[i].r++;
while(q[i].r>nr) Chg(re[++nr],1);
while(q[i].l<nl) Chg(re[--nl],1);
while(q[i].l>nl) Chg(re[nl++],-1);
while(q[i].r<nr) Chg(re[nr--],-1);
ans[q[i].id]=now;
}
}
else {
for(int i=n;i>0;i--) if((s[i]-'0')%P==0) re[i]=i,ap[i]=1;
for(int i=1;i<=n;i++) re[i]+=re[i-1],ap[i]+=ap[i-1];
for(int i=1;i<=m;i++)
ans[i]=re[q[i].r]-re[q[i].l-1]-(LL)(ap[q[i].r]-ap[q[i].l-1])*(q[i].l-1);
}
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: