BZOJ 4542: [Hnoi2016]大数

突然觉得整场省选我都是处于脑残状态

这才是两天中最简单的题

首先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[N],a[N];
int b[N],c[N],d[N];
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[N];
char s[N];
ll res[N];
#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;
}
论智商不在线的危害

你可能感兴趣的:(BZOJ 4542: [Hnoi2016]大数)