这个题思考角度很多,做法也很多。这里介绍一种 @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;
}
标签:le,const,int,Codeforces,hs2,Lemma,1ll,hs1,1909G
From: https://www.cnblogs.com/tzcwk/p/Codeforces-1909G.html