P9453 [ZSHOI-R1] 有效打击 题解
ckain
·
·
题解
首先我们将 B 做成最小形式.
设 B 被分为若干段相同的字符,将它们长度统一除以它们的 \gcd,得到串 B_{min}. 由于相似的传递性,有与 B 相似等价于与 B_{min} 相似.
与 B_{min} 相似,必须满足其是 B_{min} 放大整数倍的结果.
证明:
考虑反证.设 X 是与 B_{min} 相似的串,有
X=\frac{p}{q}B_{min}\;(\gcd(p,q)=1)
---
若 $B_{min}$ 的长度是 $1$,求解答案是容易的.
若 $B_{min}$ 的长度不是 $1$,枚举 $A$ 中可能作为 $B_{min}$ 相似串的右端点.可以发现,当固定右端点时,$B_{min}$ 被放大的倍数是确定的.
考虑字符串哈希.我们先预处理出每种放大倍数下,$B$ 串的哈希值.然后对 $A$ 串做区间哈希即可完成对每个右端点 $O(1)$ 检查.
总时间复杂度 $O(n\log n)$.瓶颈在求 $\gcd$.
code:
```cpp
#include<bits/stdc++.h>
#define pii pair<int, int>
#define fr first
#define sc second
#define int long long
using namespace std;
inline int rd(void){
int s=0, f=1; char c=getchar();
while(c<'0' || c>'9') {if(c=='-') f=0; c=getchar();}
while(c>='0' && c<='9') {s=s*10+c-'0'; c=getchar();}
return f? s:-s;
}
const int N=5e6+5, P=390831, Mod=1e9+7;
int n, m, a[N], b[N];
int pw[N], spw[N], hsha[N], hshb[N];
int len[N], c[N], tot, s;
int now[N];
void init(){
pw[0]=spw[0]=1;
for(int i=1; i<=n; i++) pw[i]=pw[i-1]*P%Mod, spw[i]=(spw[i-1]+pw[i])%Mod;
for(int i=1; i<=n; i++) hsha[i]=(hsha[i-1]*P%Mod+a[i])%Mod;
for(int i=1; i<=m; i++){
int j=i;
while(j<m && b[j+1]==b[i]) j++;
len[++tot]=j-i+1;
c[tot]=b[i];
i=j;
}
int Gcd=len[1];
for(int i=2; i<=tot; i++) Gcd=__gcd(Gcd, len[i]);
for(int i=1; i<=tot; i++) len[i]/=Gcd, s+=len[i];
for(int i=1; s*i<=n; i++){
for(int j=1; j<=tot; j++){
now[j]=(now[j-1]*pw[len[j]*i]%Mod+spw[len[j]*i-1]*c[j]%Mod)%Mod;
}
hshb[i]=now[tot];
}
}
int que(int l, int r){
return (hsha[r]-hsha[l-1]*pw[r-l+1]%Mod+Mod)%Mod;
}
void solve(){
int ans=0;
if(tot==1)
for(int i=1, prelas=-1; i<=n; i++){
if(a[i]!=c[tot]) prelas=-1;
else if(prelas==-1) prelas=i;
if(a[i]==c[tot]) ans+=(i-prelas+1);
}
else
for(int i=1, prelas=-1; i<=n; i++){
if(a[i]!=c[tot]) prelas=-1;
else if(prelas==-1) prelas=i;
if(a[i]==c[tot]){
if((i-prelas+1)%len[tot]==0){
int k=(i-prelas+1)/len[tot];
if(que(i-k*s+1, i)==hshb[k]) ans++;
}
}
}
printf("%lld\n", ans);
}
signed main(){
n=rd(), m=rd();
for(int i=1; i<=n; i++) a[i]=rd();
for(int i=1; i<=m; i++) b[i]=rd();
init();
solve();
return 0;
}
```