bzoj3172: [tjoi2013]單詞
time limit: 10 sec memory limit: 512 mb
某人讀**,一篇**是由許多單詞組成。但他發現乙個單詞會在**中出現很多次,現在想知道每個單詞分別在**中出現多少次。
input
第乙個乙個整數n,表示有多少個單詞,接下來n行每行乙個單詞。每個單詞由小寫字母組成,n<=200,單詞長度不超過10^6
output
輸出n個整數,第i行的數字表示第i個單詞在文章中出現了多少次。
sample input
3 a
aa aaa
sample output
6 3
1再是一道初識fail樹的經典題,所謂fail樹就是在構建完fail指標後,把所有的fail指標反向,變成一棵樹,每個串終點所在fail樹的子樹中cnt的總和就是這個字串的出現次數,於是每個點記錄所在fail樹的子樹中cnt的數量,可以線性時間內出解
這一大段話有點難理解(如果你是初學者的話),實際上在實現起來不用真正的建一棵fail樹,只要在makefail完成後
cnt[fail[heap[i]]]+=cnt[heap[i]];
heap記錄的是bfs的序列
這裡寫**片
#include///fail樹
#include
#include
#include
using
namespace
std;
int n;
char w[1000010];
int ch[1000010][30],tot=0,fail[1000010];
int cnt[1000010];
int word[256],tt=0,heap[1000010];
void build(int bh)
word[bh]=nw;
return;
}//這道題中字典和需要匹配的字元是一樣的,所以不用單獨再把字典中的東西跑一遍ac自動機
//在建trie時就把經過的點cnt++,相當於匹配了一遍
void make() //make fail
// fail[ch[r][i]]=ch[fail[r]][i];
if (!ch[r][i]) continue; //
int f=fail[r]; //
while(f&&!ch[f][i]) f=fail[f]; //
fail[ch[r][i]]=ch[f][i]; //
q.push(ch[r][i]);
}
}for (i=tt;i;i--)
cnt[fail[heap[i]]]+=cnt[heap[i]];
return; //在進行這一步操作時一定要按照bfs的順序!!!
}int main()
make();
for (int i=1;i<=n;i++)
printf("%d\n",cnt[word[i]]);
return
0;}
交到bzoj上發現我的用時要比其他人多很多,自行**後發現是memset的guo
上面的那一行是使用memeset後的用時
下面這一行是去掉memset後的用時
可見,memset要慎用
BZOJ3172 AC自動機 fail樹
description 某人讀 一篇 是由許多單詞組成。但他發現乙個單詞會在 中出現很多次,現在想知道每個單詞分別在 中出現多少次。input 第乙個乙個整數n,表示有多少個單詞,接下來n行每行乙個單詞。每個單詞由小寫字母組成,n 200,單詞長度不超過10 6 output 輸出n個整數,第i行的...
BZOJ 3172 單詞 (AC自動機)
這道題是個裸的ac自動機,但是我還是調了很久qaq。首先如果我們直接用每個單詞來匹配的,時間不是很理想。這道題要用到ac自動機的衍生物 fail樹 我也是做這道題才知道有這個東西 fail樹有這麼乙個結論 乙個字串出現的次數等於以它為根節點的fail樹的子樹中所有節點的cnt的和。根據這個結論,我們...
bzoj3172 單詞 AC自動機
感覺以前寫過。bzoj上不去我也不知道 跑一遍ac自動機,每乙個節點儲存一下屬於多少字串,為它的權值。然後乙個節點表示的字串在整個字典中出現的次數相當於其在fail樹中的子樹的權值的和。ac自動機不要寫掛就好了。ac 如下 include include include define n 11000...