1. 程式人生 > 實用技巧 >E. You Are Given Some Strings...

E. 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;
}