bzoj
洛谷我們先想一下最暴力是怎麼搞的
把$ac$自動機建好,每乙個節點,從$y$串的結尾節點往上跳它的父親,
和普通的$ac$自動機一樣跳就好了
然而這個可以優化一下
我們將所有詢問離線
每個串統計一次其他串對它的貢獻
就可以有$70pts$了
$70pts$**
#include #include #include #include #include #include #include using namespace std;
const int max_n = 2e5 + 5;
char s[max_n];
int n, tot, nd[max_n], ans[max_n], sum[max_n];
struct trie t[max_n];
void build()
} }int query(int y)
struct query q[max_n];
bool operator < (const query l, const query r)
int main ()
if (s[i] == 'b') o = t[o].fa;
if (s[i] == 'p') nd[++n] = o, t[o].end = n;
}build();
int m; scanf("%d", &m);
for (int i = 1; i <= m; i++) scanf("%d", &q[i].x), scanf("%d", &q[i].y), q[i].id = i;
sort(&q[1], &q[m + 1]);
for (int i = 1, j = 1; i <= m; i = j)
for (int i = 1; i <= m; i++) printf("%d\n", ans[i]);
return 0;
}
然後我們想一下這個過程:
每乙個點往上跳,如果可以跳到乙個點,是其他字串的$end$節點就統計貢獻
所以對於乙個點,它跳到它被匹配的模式串的$end$點的次數,就是答案
換句話說
對於每個模式串,就是要統計有多少個文字串能跳到它。
這個就好解決一些了,
發現對於每個點,它對應的$fail$只有乙個
所以我們將點$i$與$fail_i$連邊,
在新的樹上統計:
每次將串$i$的鏈上加一,然後將詢問離線統計貢獻。
但是這樣做還是只有$70pts$,
因為還是有很多狀態被重複統計,
那麼如何繼續優化呢?
接下來的做法就很巧妙了:
我們保留原來的$trie$和根據$fail$新建的樹
在新樹上預處理$dfs$序,
然後$dfs$遍歷一遍原$trie$,入棧時將這個點$+1$
出棧時$-1$
如果這個點有結尾的串,就對這個串統計貢獻,
因為我們$dfs$回答詢問時只會有那乙個串被統計
所以我們的做法是對的。
如有什麼不理解的地方,可以參見**
**
#include #include #include #include #include #include #include #include using namespace std;
const int max_n = 2e5 + 5;
char s[max_n];
int n, tot, nd[max_n], ans[max_n];
struct trie t[max_n];
void build()
} } struct graph e[max_n << 1]; int fir[max_n], e_cnt = 0;
void cleargraph()
void add_edge(int u, int v) , fir[u] = e_cnt++; }
struct query ;
vectorvec[max_n];
int tim, l[max_n], r[max_n];
void dfs(int x)
int c[max_n];
inline int lb(int x)
void add(int x, int v)
int sum(int x)
void dfs(int x)
int main ()
if (s[i] == 'b') o = t[o].fa;
if (s[i] == 'p') nd[++n] = o, t[o].end = n;
} for (int i = 0; i <= tot; i++)
for (int o = 0; o < 26; o++) t[i].cpy[o] = t[i].ch[o];
build(); cleargraph();
for (int i = 1; i <= tot; i++) add_edge(t[i].fail, i);
dfs(0);
int m; scanf("%d", &m);
for (int i = 1; i <= m; i++) );
} dfs(0);
for (int i = 1; i <= m; i++) printf("%d\n", ans[i]);
return 0;
}
BZOJ2434 NOI2011 阿狸的打字機
發現一種新的思路,以前從來沒有見過的,即ac自動機的fail樹。這一題我們先考慮暴力,從root往y的最後乙個點走,如果走到了x的末點,ans 如果通過fail指標走到了x的末點,ans 反過來考慮,從x的末點開始,如果當前點在y串或者通過反向的fail到了y串,ans 又發把fail反向之後得到的...
bzoj2434 Noi2011 阿狸的打字機
傳送門 description 阿狸喜歡收藏各種稀奇古怪的東西,最近他淘到一台老式的打字機。打字機上只有28個按鍵,分別印有26個小寫英文本母和 b p 兩個字母。經阿狸研究發現,這個打字機是這樣工作的 l 輸入小寫字母,打字機的乙個凹槽中會加入這個字母 這個字母加在凹槽的最後 l 按一下印有 b ...
bzoj 2434 Noi2011 阿狸的打字機
time limit 10 sec memory limit 256 mb submit 3139 solved 1731 submit status discuss 阿狸喜歡收藏各種稀奇古怪的東西,最近他淘到一台老式的打字機。打字機上只有28個按鍵,分別印有26個小寫英文本母和 b p 兩個字母。...