HNOI2016大数


\(n1e5\)

数据范围这么小,莫队啊!

\(suf_i\)为后缀除以p的余数

那么区间\([l,r]\)整除\(p\to\frac{suf_l-suf_{r+1}}{10^{n-r}}=0\)

  1. \(gcd(10,p)=1\to suf_l=suf_{r+1}\)求区间\([l,r+1]\)内相同数的对数,莫队,时间复杂度\(O(n\sqrt n)\)
  2. 否则,2,5的倍数用看末尾数,时间复杂度\(O(n)\)

推式子!!

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=1e5+4,B=500;
int n,m,p,c[N],s[N],ans[N];
char ch[N];
inline void work(){
	for(int i=1;i<=n;i++){
		if((p==2&&!((ch[i]^48)&1))||(p==5&&((ch[i]^48)==0||(ch[i]^48)==5))){
			s[i]=i;
			c[i]=1;
		}
		s[i]+=s[i-1];
		c[i]+=c[i-1];
	}
	while(m--){
		static int l,r;
		l=read();r=read();
		cout<<s[r]-s[l-1]-(l-1)*(c[r]-c[l-1])<<"\n";
	}
}
struct ques{
	int l,r,id;
}q[N];
inline bool comp(const ques &x,const ques &y){
	return x.l/B==y.l/B?x.r<y.r:x.l/B<y.l/B;
}
signed main(){
	p=read();
	scanf("%s",ch+1);
	n=strlen(ch+1);
	m=read();
	if(p==2||p==5){work();return (0-0);}
	for(int i=1;i<=m;i++){
		q[i].l=read();q[i].r=read()+1;
		q[i].id=i;
	}	
	sort(q+1,q+m+1,comp);
	for(int i=n,mi=1;i;i--,(mi*=10)%=p)
		c[i]=s[i]=((ch[i]^48)*mi+s[i+1])%p;
	sort(c+1,c+n+2);
	int cn=unique(c+1,c+n+2)-c-1;
	for(int i=1;i<=n+1;i++)
		s[i]=lower_bound(c+1,c+cn+1,s[i])-c;
	memset(c,0,sizeof(c));
	for(int i=1,l=1,r=0,nw=0;i<=m;i++){
		while(r<q[i].r){
			++r;
			nw+=c[s[r]];
			++c[s[r]];
		}
		while(q[i].r<r){
			--c[s[r]];
			nw-=c[s[r]];
			--r;
		}
		while(l<q[i].l){
			--c[s[l]];
			nw-=c[s[l]];
			++l;
		}
		while(q[i].l<l){
			l--;
			nw+=c[s[l]];
			c[s[l]]++;
		}
		ans[q[i].id]=nw;
	}
	for(int i=1;i<=m;i++)cout<<ans[i]<<"\n";
	return (0-0);
}

猜你喜欢

转载自www.cnblogs.com/aurora2004/p/12656593.html