Codeforces 1909G - Pumping Lemma

这个题思考角度很多,做法也很多。这里介绍一种 @asmend 和我讲的做法。

\(d=m-n\),那么我们枚举 \(|x|=i,|y|=j\),设 \(s,t\) 的 LCP 长为 \(l_1\),LCS 长为 \(l_2\),那么可以得到这组 \((i,j)\) 合法的充要条件是:

  • \(i\le l_1\)
  • \(m-i-j-d\le l_2\)
  • \(d\bmod j=0\)
  • \(t[i,i+d-1]=t[i+j,i+j+d-1]\)

考虑第四条限制,我们将所有长度为 \(d\) 的子串的哈希值排序,这样对于每种子串,我们可以知道其出现的位置 \(p_1,p_2,\cdots,p_c\)。考虑 occurrence 序列的一个性质:对于极长的满足 \(p_{l+1}-p_l\le d,p_{l+2}-p_{l+1}\le d,\cdots,p_r-p_{r-1}\le d\) 的连续段 \([l,r]\),必然有 \(p_{l+1}-p_l=p_{l+2}-p_{l+1}=\cdots=p_r-p_{r-1}\),这个可以用 WPL 证明。这样考虑对每个这样的连续段统计贡献,设等差数列的公差为 \(t\),长度为 \(c\),因为是等差数列,因此这个连续段内部可能出现的 \(j\) 只有 \(t,2t,\cdots,(c-1)t\)\(O(c)\) 种,枚举之,那么第一、二条限制的作用是将 \(i\) 限制在一个区间内,这样相当于求等差数列中在这个区间内的数的个数,这容易 \(O(1)\)。因为 \(\sum c=O(n)\),所以后面复杂度为线性。复杂度瓶颈在排序,如果使用三个与 \(n\) 同阶的质数作为哈希模数并桶排则可以线性。但我直接 sort 以 1996ms 卡了过去就没管了(

const int MAXN=1e7;
const int MOD1=1e9+21;
const int MOD2=1e9+33;
const int BS1=191;
const int BS2=193;
int qpow(int x,int e,int mod){int ret=1;for(;e;e>>=1,x=1ll*x*x%mod)if(e&1)ret=1ll*ret*x%mod;return ret;}
char s[MAXN+5],t[MAXN+5];int n,m,d,pw1,pw2;
struct _hash{
	int hs1,hs2,pos;
	_hash(){hs1=hs2=pos=0;}
	void append(int x){
		hs1=(1ll*hs1*BS1+x)%MOD1;
		hs2=(1ll*hs2*BS2+x)%MOD2;
	}
	void del(int x){
		hs1=(hs1+1ll*(MOD1-pw1)*x)%MOD1;
		hs2=(hs2+1ll*(MOD2-pw2)*x)%MOD2;
	}
	friend bool operator <(const _hash &X,const _hash &Y){
		if(X.hs1!=Y.hs1)return X.hs1<Y.hs1;
		if(X.hs2!=Y.hs2)return X.hs2<Y.hs2;
		return X.pos<Y.pos;
	}
	friend bool operator ==(const _hash &X,const _hash &Y){
		return (X.hs1==Y.hs1&&X.hs2==Y.hs2);
	}
}a[MAXN+5],cur;
int limL,limR;ll res=0;
int calc(int l,int r,int stp,int rem){
	if(l>r)return 0;
	return (r-rem+stp)/stp-(l-1-rem+stp)/stp;
}
void work(int l,int r){
	for(int i=l;i<r;i++)res+=(a[i+1].pos-a[i].pos==d);
	for(int L=l,R;L<=r;L=R+1){
		if(a[L].pos>limR)break;
		R=L;while(R<r&&a[R+1].pos-a[R].pos<d)++R;
		if(L!=R){
			int d0=a[L+1].pos-a[L].pos;
			for(int j=1;j<=R-L;j++)if(d%(j*d0)==0){
				int _R=limR,_L=limL-j*d0;
				res+=calc(max(_L,a[L].pos),min(_R,a[R-j].pos),d0,a[R].pos%d0);
			}
		}
	}
}
int main(){
	scanf("%d%d%s%s",&n,&m,s+1,t+1);d=m-n;
	pw1=qpow(BS1,d,MOD1);pw2=qpow(BS2,d,MOD2);
	for(int i=1;i<=m;i++){
		cur.append(t[i]);
		if(i>d)cur.del(t[i-d]);
		if(i>=d)a[i-d+1]=cur,a[i-d+1].pos=i-d+1;
	}
	sort(a+1,a+m-d+2);
//	for(int i=1;i<=m-d+1;i++)printf("(%d,%d,%d) %d\n",a[i].hs1,a[i].hs2,a[i].hs3,a[i].pos);
	int len1=0,len2=0;
	while(len1<n&&s[len1+1]==t[len1+1])++len1;
	while(len2<n&&s[n-len2]==t[m-len2])++len2;
	limR=len1+1;limL=m-len2-d+1;
	for(int l=1,r;l<=m-d+1;l=r){
		r=l;while(r<=m-d+1&&a[r]==a[l])++r;
		work(l,r-1);
	}
	printf("%lld\n",res);
	return 0;
}
posted @ 2023-12-26 10:47  tzc_wk  阅读(62)  评论(0编辑  收藏  举报