您的位置:首页 > 其它

BZOJ 4542: [Hnoi2016]大数

2016-04-19 14:16 302 查看
突然觉得整场省选我都是处于脑残状态

这才是两天中最简单的题

首先p为2,5的时候特判一下,所有以p的倍数结尾的大数都是p的倍数

然后令a[i]为以i为左端点的后缀数模p的结果,显然number(l,r)=(a[l]-a[r+1])/(10^(n-r))

即a[l]-a[r+1]=number(l,r)*10^(n-r),显然10的任意次方与p互质,所以要想number(l,r)是p的倍数,那么a[l]==a[r+1],于是问题就是求区间[l,r+1]内相等的数对个数,上莫队就好了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=100000+5;
typedef long long ll;
ll hash
,a
;
int b
,c
,d
;
struct Query{
int l,r,id;
bool operator < (const Query &x)const{
return b[l]==b[x.l]?r<x.r:b[l]<b[x.l];
}
}q
;
char s
;
ll res
;
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
int main(){
//freopen("a.in","r",stdin);
ll p;scanf("%lld",&p);
scanf("%s",s+1);int n=strlen(s+1);
if(p==2||p==5){
rep(i,1,n)if((s[i]-'0')%p==0)a[i]=i,b[i]=1;
rep(i,1,n)a[i]+=a[i-1],b[i]+=b[i-1];
int m;scanf("%d",&m);
while(m--){
int l,r;scanf("%d%d",&l,&r);
printf("%lld\n",a[r]-a[l-1]-(ll)(l-1)*(b[r]-b[l-1]));
}
}else{
ll ten=1;
per(i,n,1)a[i]=(a[i+1]+(s[i]-'0')*ten)%p,ten=ten*10%p;
n++;rep(i,1,n)hash[i]=a[i];
sort(hash+1,hash+1+n);
rep(i,1,n)d[i]=lower_bound(hash+1,hash+1+n,a[i])-hash;
int block=sqrt(n+0.5);
rep(i,1,n)b[i]=(i-1)/block;
int m;scanf("%d",&m);
rep(i,1,m)scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i,q[i].r++;
sort(q+1,q+1+m);
int ql=1,qr=0;ll ans=0;
rep(i,1,m){
while(qr<q[i].r)ans+=c[d[++qr]]++;
while(q[i].l<ql)ans+=c[d[--ql]]++;
while(ql<q[i].l)ans-=--c[d[ql++]];
while(q[i].r<qr)ans-=--c[d[qr--]];
res[q[i].id]=ans;
}
rep(i,1,m)printf("%lld\n",res[i]);
}
return 0;
}
论智商不在线的危害
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: