CF1202E You Are Given Some Strings...
CF1202E You Are Given Some Strings...
下午这紫题2400看半天不会然后去做了黑题2700.晚上又回来搞这题.
What an easy problem!How stupid I am! 真的只有2400啊
关键在于想到枚举分界点
我们发现答案可以分为两部分统计:
-
是 \(T_{1,\cdots,i}\) 后缀的模式串个数 \(f_i\)
-
是 \(T_{i,\cdots,len}\) 前缀的模式串个数 \(g_i\)
那么 \(ans=\sum f_{i-1}\times g_i\)
那两部分看着就很AC自动机, 但是我没学扎实,都想到这里了还写了1h
第一部分
首先,必然是让文本串沿着 \(Trie\) 图跑,因为那代表的是它前缀的状态.
那么现在的任务是对于 \(Trie\) 图上的每个节点统计"有几个模式串是它的后缀"
这时往往借助 \(fail\) 树来求解
记 \(cnt_i\) 表示 \(Trie\) 树上,以那个节点为终止节点的模式串数量
考虑在 \(fail\) 树上通过一次下放得出每个节点的 \(cnt_i\) ,即对于每一个节点求出求出"有几个模式串是它的后缀"
由于在 \(fail\) 树上,父节点是子节点的后缀,那么子节点的 \(cnt\) 应该加上父节点的 \(cnt\)
所以下放一次就完事了
第二部分
把所有模式串翻转一下,倒着扫文本串让它在 \(Trie\) 图上跑求 \(g_i\) 即可
如果能理解第一部分第二部分应该是显然的.
但是注意:如果不翻转所有文本串也能过样例,然后 WA on test 6
可以被下面这组数据卡掉
Input
abcdabcd
4
d
cd
a
ab
Output
6
其实这个数据加上题目里两个样例结合起来用是非常强劲的数据,都过了基本上就能AC.很多时候只能过一个或两个,那就会WA
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double db;
#define x first
#define y second
#define sz(v) (int)v.size()
#define pb(x) push_back(x)
#define mkp(x,y) make_pair(x,y)
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=0;c=getchar();}
while(isdigit(c))x=x*10+c-'0',c=getchar();
return f?x:-x;
}
#define N 200005
string T,str[N];
int n,f[N],g[N];
LL cnt[N];
int ch[N][26],tot,fail[N];
LL ans;
vector<int>e[N];
void clear(){
for(int i=0;i<=tot;++i)e[i].clear();
tot=0;
memset(cnt,0,sizeof(cnt));
memset(ch,0,sizeof(ch));
memset(fail,0,sizeof(fail));
}
void insert(string str){
int u=0;
for(int i=0;i<sz(str);++i){
int c=str[i]-'a';
if(!ch[u][c])ch[u][c]=++tot;
u=ch[u][c];
}
++cnt[u];
}
void build_fail(){
queue<int>q;
for(int i=0;i<26;++i)if(ch[0][i])q.push(ch[0][i]);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;++i)
if(ch[u][i])fail[ch[u][i]]=ch[fail[u]][i],q.push(ch[u][i]);
else ch[u][i]=ch[fail[u]][i];
}
for(int i=1;i<=tot;++i)e[fail[i]].pb(i);
}
void dfs(int u){
for(int v:e[u])cnt[v]+=cnt[u],dfs(v);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T>>n;
for(int i=1;i<=n;++i)cin>>str[i];
for(int i=1;i<=n;++i)insert(str[i]);
build_fail(),dfs(0);
for(int u=0,i=0;i<sz(T);++i)u=ch[u][T[i]-'a'],f[i]=cnt[u];
clear();
for(int i=1;i<=n;++i)reverse(str[i].begin(),str[i].end()),insert(str[i]);
build_fail(),dfs(0);
for(int u=0,i=sz(T)-1;~i;--i)u=ch[u][T[i]-'a'],g[i]=cnt[u];
for(int i=1;i<sz(T);++i)ans+=1ll*f[i-1]*g[i];
cout<<ans<<'\n';
return 0;
}
upd:我发现一个非常严重的问题,大概是因为我用了cin和string,是个人代码就跑得比我块>_<