E. You Are Given Some Strings...
阿新 • • 發佈:2020-10-27
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\)
如果能理解第一部分第二部分應該是顯然的.
但是注意:如果不翻轉所有文字串也能過樣例,然後會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; }