Loading

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,是个人代码就跑得比我块>_<

posted @ 2020-10-27 20:03  zzctommy  阅读(43)  评论(0编辑  收藏  举报