Luogu 3245 大数

Luogu 3245 大数

  • 开始就想 (10) 进制 (hash) ,(Hash(r)equiv Hash(l-1)cdot 10^{r-l+1}) ,感觉没什么美妙的性质啊...
  • 然后把 (hash) 换个方向,先加低位,再加高位,就成了 (frac {Hash(l)-Hash(r+1)} {10^{n-r}}equiv 0) ,似乎,就很美妙了?
  • (P ot=2,5) 时,下面的分母有逆元,那么只能是 (Hash(l)equiv Hash(r+1)) ,就变成了在一段区间内问相同元素的对数,离散化之后,用莫队可以解决.
  • (P=2,5) 时,一段区间内仅有以 (P,0) 结尾的串符合条件,计数相当简单.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
	int out=0,fh=1;
	char jp=getchar();
	while ((jp>'9'||jp<'0')&&jp!='-')
		jp=getchar();
	if (jp=='-')
		fh=-1,jp=getchar();
	while (jp>='0'&&jp<='9')
		out=out*10+jp-'0',jp=getchar();
	return out*fh;
}
const int MAXN=1e5+10;
int n,m,P;
inline int add(int a,int b)
{
	return (a + b) % P;
}
inline int mul(int a,int b)
{
	return 1LL * a * b % P;
}
struct query
{
	int l,r,id,bel;
	bool operator < (const query &rhs) const
	{
		if(bel!=rhs.bel)
			return bel<rhs.bel;
		if(r!=rhs.r)
			return r<rhs.r;
		return l<rhs.l;
	}
}q[MAXN];
char buf[MAXN];
int Hash[MAXN],cp[MAXN];
int cnt[MAXN];
ll ans[MAXN],res;
void add(int x)
{
	res+=cnt[Hash[x]];
	++cnt[Hash[x]];
}
void rem(int x)
{
	--cnt[Hash[x]];
	res-=cnt[Hash[x]];
}
int sumcnt[MAXN],sumpos[MAXN];
void solve_spj()
{
	for(int i=1;i<=n;++i)
	{
		if(buf[i]-'0'==0 || buf[i]-'0'==P)
			sumcnt[i]=1,sumpos[i]=i;
		sumcnt[i]+=sumcnt[i-1];
		sumpos[i]+=sumpos[i-1];
	}
	m=read();
	for(int i=1;i<=m;++i)
	{
		int l=read(),r=read();
		ll cntsum=sumcnt[r]-sumcnt[l-1],possum=sumpos[r]-sumpos[l-1];
		ll res=possum-1LL*(l-1)*cntsum;
		printf("%lld
",res);
	}
}
int main()
{
	P=read();
	scanf("%s",buf+1);
	n=strlen(buf+1);
	if(P==2 || P==5)
	{
		solve_spj();
		return 0;
	}
	int pow10=1;
	for(int i=n;i>=1;--i)
	{
		cp[i]=Hash[i]=add(Hash[i+1],mul(buf[i]-'0',pow10));
		pow10=mul(pow10,10);
	}
	++n;//0
	sort(cp+1,cp+1+n);
	int tot=unique(cp+1,cp+1+n)-cp-1;
	for(int i=1;i<=n;++i)
		Hash[i]=lower_bound(cp+1,cp+1+tot,Hash[i])-cp;
	m=read();
	int BlockSize=sqrt(m);
	for(int i=1;i<=m;++i)
	{
		q[i].l=read();
		q[i].r=read();
		q[i].id=i;
		q[i].bel=q[i].l/BlockSize;
	}
	sort(q+1,q+1+m);
	int L=1,R=0;
	for(int i=1;i<=m;++i)
	{
		int l=q[i].l,r=q[i].r;
		++r;
		if(l==r)
			continue;
		while(R<r)
			add(++R);
		while(L<l)
			rem(L++);
		while(L>l)
			add(--L);
		while(R>r)
			rem(R--);
		ans[q[i].id]=res;
	}
	for(int i=1;i<=m;++i)
		printf("%lld
",ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/jklover/p/10685841.html