[CF452E]Three strings
题目
题解
算法一
暴力做,枚举 \(A\) 的字串,在 \(B,C\) 中暴力找,时间复杂度 \(\mathcal O(n^4)\).
算法二
同样要在 \(A\) 中枚举字串,但是考虑在 \(L=1\) 时,对于 \(A\) 的每个字符,我们可以在 \(B,C\) 中找出相匹配的,随着 \(L\) 变大,可能的相同的部分也只可能在之前匹配的字符之后出现,所以我们可以考虑用类似于 vector
一类的东西将位置存下来,时间复杂度 \(\mathcal O(\tt{TLE})\).
算法三(SA)
考虑使用 \(\tt SA\) 将字符串匹配转换为 \(\tt LCP\) 问题.
首先,处理这种问题的关键是我们得将 \(A,B,C\) 首尾相接得到 \(S\),中间使用分隔符隔开,接下来我们称其为 \(S\) 的 \(A,B,C\) 三个部分.
接下来,字符串内部的匹配问题就转化为后缀的 \(\tt LCP\) 问题,对于原来 \(A,B,C\) 三个串长度为 \(L\) 的匹配,现在即为属于三个不同部分的后缀的 \(\texttt{LCP} \ge L\) 即可.
但是,对于不同的部分,他们的 \(\tt LCP\) 并非是单调的,比如我们有个后缀排序的数组长这样
对于 \(L=4\) 时,可能有这些部分的 \(\tt LCP\) 是满足条件的
那么 \(\tt ans[4]\) 就是各个部分的 \(\tt cnt[A] \cdot cnt[B] \cdot cnt[C]\),其中 \(\tt cnt[i]\) 表示属于 \(i\) 部分的后缀的个数.
但是,随着 \(L\) 变大,各个部分有可能会断开,这让我们非常不好处理,既然 \(L\) 变大会断开,那么同样意味着,如果我们倒着处理 \(L\),那么随着 \(L\) 的变小,会有越来越多的部分连接在一起,这个时候我们只需要维护 cnt[i]
即可,而这个部分可以使用并查集来做,并查集合并的时候,我们也可以维护答案.
关键代码:
const int jzm=1000000007;
/** @brief 全局答案*/
int sy=0;
/** @brief 对应长度的答案*/
int ans[maxn+5];
struct node{
// x 是后缀编号
int x,v;
inline int operator <(const node rhs)const{
return v>rhs.v;
}
}v[maxn+5+5];
int fa[maxn+5];
int find(const int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int cock(const int x){
return 1ll*tot[x][1]*tot[x][2]%jzm*tot[x][3]%jzm;
}
inline void merge(int x,int y){
// printf("merge:> x == %d, y == %d\n",x,y);
x=find(x),y=find(y);
if(x==y)return;
sy-=cock(x);if(sy<0)sy+=jzm;
sy-=cock(y);if(sy<0)sy+=jzm;
fa[x]=y;
rep(j,1,3)tot[y][j]+=tot[x][j];
sy+=cock(y);
if(sy>=jzm)sy-=jzm;
}
inline void solve(){
rep(i,1,n)v[i]=node{sa[i],heit[i]};
rep(i,1,n)fa[i]=i;
sort(v+1,v+n+1);
// rep(i,1,n)printf("v[%d] : x == %d, v == %d\n",i,v[i].x,v[i].v);
int now=1;
fep(i,min_len,1){
while(now<=n && v[now].v>=i){
// printf("When i == %d, now == %d\n",i,now);
int pre=sa[rk[v[now].x]-1];
merge(pre,v[now].x);
++now;
}
ans[i]=sy;
}
rep(i,1,min_len)printf("%d ",ans[i]);
}
算法四(SAM)
广义自动机板题.
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
namespace Elaina{
#define rep(i,l,r) for(int i=l,i##_end_=r;i<=i##_end_;++i)
#define fep(i,l,r) for(int i=l,i##_end_=r;i>=i##_end_;--i)
#define fi first
#define se second
#define Endl putchar('\n')
#define writc(x, c) fwrit(x),putchar(c)
// # define int long long
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef unsigned int uint;
template<class T>inline T Max(const T x,const T y){return x<y?y:x;}
template<class T>inline T Min(const T x, const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x<0?-x:x;}
template<class T>inline void getMax(T& x, const T y){x=Max(x,y);}
template<class T>inline void getMin(T& x, const T y){x=Min(x,y);}
template<class T>T gcd(const T x,const T y){return y?gcd(y,x%y):x;}
template<class T>inline T readin(T x){
x=0;int f = 0;char c;
while((c=getchar())<'0'||'9'<c)if(c=='-')f=1;
for(x=(c^48);'0'<=(c=getchar())&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
template<class T>void fwrit(const T x){
if(x<0)return putchar('-'),fwrit(-x);
if(x>9)fwrit(x/10);putchar(x%10^48);
}
}
using namespace Elaina;
const int maxn=3e5;
const int mod=1e9+7;
int trie[maxn*2+5][26];
int fa[maxn*2+5],len[maxn*2+5];
int cnt=1,lst;
int sz[maxn*2+5][3];
inline void add(const int c,const int col){
// printf("add :> c == %d, col == %d\n",c,col);
int p=lst,u,q,nq;
if(trie[p][c]){
q=trie[p][c];
if(len[q]==len[p]+1)lst=q;
else{
int nq=lst=++cnt;
rep(i,0,25)trie[nq][i]=trie[q][i];
fa[nq]=fa[q],len[nq]=len[p]+1;
fa[q]=nq;
for(;p&&trie[p][c]==q;p=fa[p])trie[p][c]=nq;
}
++sz[lst][col];
return;
}
u=lst=++cnt;
len[u]=len[p]+1,++sz[u][col];
for(;p&&!trie[p][c];p=fa[p])trie[p][c]=u;
if(!p)fa[u]=1;
else{
q=trie[p][c];
if(len[q]==len[p]+1)fa[u]=q;
else{
nq=++cnt;
rep(i,0,25)trie[nq][i]=trie[q][i];
fa[nq]=fa[q],len[nq]=len[p]+1;
fa[q]=fa[u]=nq;
for(;p&&trie[p][c]==q;p=fa[p])trie[p][c]=nq;
}
}
}
char s[maxn+5];
int n,ans[maxn+5];
struct edge{int to,nxt;
edge(const int T=0,const int N=0):to(T),nxt(N){}
}e[maxn*2+5];
int tail[maxn*2+5],ecnt;
inline void add_edge(const int u,const int v){
// printf("add_edge :> u == %d, v == %d\n",u,v);
e[++ecnt]=edge(v,tail[u]);tail[u]=ecnt;
}
void dfs(const int u){
for(int i=tail[u],v;i;i=e[i].nxt){
dfs(v=e[i].to);
rep(j,0,2)sz[u][j]+=sz[v][j];
}
// printf("node %d :>\n",u);
// rep(i,0,2)printf("sz[%d][%d] == %d\n",u,i,sz[u][i]);
(ans[len[fa[u]]+1]+=1ll*sz[u][0]*sz[u][1]%mod*sz[u][2]%mod)%=mod;
(ans[len[u]+1]+=mod-1ll*sz[u][0]*sz[u][1]%mod*sz[u][2]%mod)%=mod;
}
signed main(){
n=maxn+5;
rep(t,0,2){
scanf("%s",s+1);lst=1;
// puts(s+1);
int len=strlen(s+1);n=Min(n,len);
rep(i,1,len)add(s[i]-'a',t);
}
rep(i,2,cnt)add_edge(fa[i],i);
dfs(1);
/*
rep(i,1,cnt)++c[len[i]];
rep(i,1,n)c[i]+=c[i-1];
fep(i,cnt,1)a[len[i]--]=i;
fep(i,cnt,2)rep(j,0,2)
sz[fa[a[i]]][j]+=sz[a[i]][j];
rep(i,2,cnt){
ans[len[i]]+=1ll*sz[i][0]*sz[i][1]%mod*sz[i][2]%mod;
ans[len[i]]%=mod;
}
*/
rep(i,1,n)ans[i]=(ans[i]+ans[i-1])%mod;
rep(i,1,n)writc(ans[i],' ');
return 0;
}