BZOJ2806 字尾自動機 DP

2021-06-18 04:36:43 字數 1561 閱讀 1374

題目:

題意:給定乙個由m個01串組成的字典。依據這個字典和乙個閥值l,可以斷言乙個01串是否"熟悉",其定義是:

把乙個串劃分成若干段,如果某個段的長度不小於l,且是字典中的某個串的連續子串,則這個段可識別;如果對於給出的串,

在乙個劃分,使得可識別的長度不小於總長度的90%,則這串是"熟悉"的。先後給出n個01串。對於每個給出的串,求使得該

串"熟悉"的最大的l值。如果這樣的l值不存在,輸出0。 輸入資料總長<=1100000。

分析:字尾自動機是用來求出給定文章最長的在模板中出現的字串的長度。把文章在模板上匹配

就行了,記錄每一位的最大匹

長度就行了。

然後我們二分答案,然後按照答案的限制求得最大匹配字元數。dp的方程很容易求得:f[i]=max。然後,假設二分的答案是limit,某位置的最大匹配長度是v[i],決策區間就是[i-v[i],i-limit],由於i-limit是

逐步增加

的,那麼每一次只需要往佇列裡新增i-limit這個點,然後判斷隊首是否在決策區間裡,即是否q[head]>=i-v[i]。

那麼此時

調佇列裡的元素都在決策區間裡。這樣就可以用隊首元素的到最優的f[i]了。最後判斷一下是否滿足比例大於等於

0.9即可。

#include #include #include #include using namespace std;

const int n=2500005;

struct state

}*root,*last;

state statepool[n*2],*cur;

void init()

void insert(int w)

}last=np;

}char str[n];

int q[n],dp[n],v[n];

int n,m;

void match(char *str)

else

v[i+1]=cnt;

}}bool judge(int limit,int len)

while(head<=tail&&q[head]=9*len;

}int main()

else r=mid-1;

}printf("%d\n",ans);

}return 0;

}

SPOJ NSUBSTR 字尾自動機 DP

給乙個長度為s的字串,問長度為1 s的子串最多出現了多少次。dp其實是非常簡單的。主要就是乙個字尾自動機的模板,敲對了就行。至於演算法,認真觀察字尾自動機,對字尾自動機理解透徹了就發現這是一道模板題。對於這道題,我發現的規律就是,對於乙個點我們很容易算出來出現次數,然後的話我們可以看一下這個點對應的...

BZOJ3238 差異 字尾自動機 dp

題意 分析這個題目還是很優秀的。sigma len ti len tj 的值是一定的 n n 1 n 1 2。那麼關鍵就是求任意兩個字尾的lcp的和了。我們怎麼求兩個字尾的lcp?如果用字尾自動機的話,我們可以先把字串反過來,然後建字尾自動機,那麼兩個字尾的lcp就是他們兩個在parent樹上的最近...

bzoj3998 字尾自動機

對於乙個給定長度為n的字串,求它的第k小子串是什麼。第一行是乙個僅由小寫英文本母構成的字串s 第二行為兩個整數t和k,t為0則表示不同位置的相同子串算作乙個。t 1則表示不同位置的相同子串算作多個。k的意義如題所述。輸出僅一行,為乙個數字串,為第k小的子串。如果子串數目不足k個,則輸出 1 aabc...