1. 程式人生 > 其它 >Codeforces 1483F - Exam(AC 自動機)

Codeforces 1483F - Exam(AC 自動機)

Codeforces 題目傳送門 & 洛谷題目傳送門

一道 ACAM 的 hot tea

首先建出 ACAM。考慮列舉長串,以及短串在長串中出現的最後位置 \(j\),這個複雜度顯然是 \(\mathcal O(\sum|s_i|)\) 的不會出問題。那麼顯然只有以 \(s_{i,j}\) 為結尾的、長度最長的字串才有可能被統計進答案,否則就不滿足題目中的條件了,而這個字串,顯然就是 \(s_{i,j}\) 對應位置在 fail 樹上向上跳得到的第一個是某個字串結尾的位置所對應的字串,這個可以通過對 fail 樹進行一遍 DFS 求出。

其次,仔細想想就會發現這些字串也並不是所有都真的符合條件,如果我們把這一個個字串看作一個個框,那麼如果一個框被另一個框完全包含,那顯然也是不合法的,這個可以通過記錄個啥陣列然後線性掃一遍把這些不合法的排除掉。但是再即便是排除掉這些不合法的字串之後也有可能出現不合法,或者同一字串被重複統計的情況,因為對於一個未被排除掉的字串 \(s_i[l...r]\)

,有可能存在它的另一個出現位置 \(s_i[l'...r']\),滿足 \(s_i[l'...r']\) 不是以 \(s_{i,r'}\) 結尾的長度最長的符合要求的字串,或者是以 \(s_{i,r'}\) 結尾的長度最長的符合要求的字串但被另外一個框完全包含。怎麼 check 這樣的情況呢?好辦,拿個 map 記錄一下所有字串在 \(s_i\) 中被統計的次數,然後在 map 裡面掃描一遍看所有字串 \(s'\)\(s_i\) 中出現次數是否等於其被統計的次數,如果是則答案加 \(1\),否則說明 \(s'\) 肯定有被排除掉的情況,就不能產生貢獻了。

時間複雜度 \(|S|\log|S|\)

const int MAXN=1e6; 
int n,ch[MAXN+5][28],ncnt=0,fail[MAXN+5],ed[MAXN+5],ps[MAXN+5];
string s[MAXN+5];
void insert(string s,int id){
	int cur=0;
	for(int i=0;i<s.size();i++){
		if(!ch[cur][s[i]-'a']) ch[cur][s[i]-'a']=++ncnt;
		cur=ch[cur][s[i]-'a'];
	} ed[id]=cur;ps[cur]=id;
}
int hd[MAXN+5],to[MAXN+5],nxt[MAXN+5],ec=0,bgt[MAXN+5],edt[MAXN+5],tim;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
void getfail(){
	queue<int> q;
	for(int i=0;i<26;i++) if(ch[0][i]) q.push(ch[0][i]);
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=0;i<26;i++){
			if(ch[x][i]) fail[ch[x][i]]=ch[fail[x]][i],q.push(ch[x][i]);
			else ch[x][i]=ch[fail[x]][i];
		}
	}
	for(int i=1;i<=ncnt;i++) adde(fail[i],i);
}