BZOJ2434 NOI2011 阿狸的打字機

2022-05-07 20:27:07 字數 2767 閱讀 9636

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 兩個字母。...