題目:
題意:給定乙個由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...