\(C_n^m\)的typora,點了一下啓用源代碼模式
就把我已經寫好的博客弄沒了,就給我留個標題,自動保存也只給我保存了個標題……\(C_n^m\),wdnmd數組
Time limit
1000 msspa
Memory limit
262144 kB.net
打比賽的時候愣是想不到怎麼用KMP,總想着若是用kmp,那麼每次合併都要更新nxt數組,會被卡到n方,就是想不到老字符串不用每次都全體參與KMP,每次只須要把老字符串後面那段拿出來判斷就好了……還想着是否是要用啥我如今還不會的高級玩意……對KMP的理解只停留在作最裸的那種板題……指針
KMP有兩種玩法,目的都是在合併老字符串(以前合併的結果)和新字符串(最新讀入的)的時候找出能夠被合併的長度,而後就能把新字符串後面那截不能合併的接到老字符串後面。邊寫邊罵typora。因爲合併的時候,老字符串和新字符串重複的長度小於等於新字符串的長度,因此處理的時候都截取老字符串後面和新字符串等長的一截(若是新字符串比老字符串長,那麼就選整個老字符串)code
一種是官方題解的思路——先把新字符串放前面,把「老字符串的後面一截」放後面,而後對於這個新接的合體字符串跑一遍KMP,求出nxt數組,以便找到最長的border(這個是nxt數組的定義了),這個就是能夠合併的長度了,固然這個值要是大於了讀入的新字符串或者以前合併出來的老字符串的長度,就要取「最長border長度、讀入的新字符串的長度、以前合併的老字符串的長度」這三者的最小值,由於合併兩個字符串最多就是一個把另外一個吞併了,長度不會小於兩個字符串中的任意一個。blog
另外一種思路來自這篇博客——每次讀入新字符串之後,把新字符串做爲模式串,把老字符串的後面那截做爲文本串。而後就跑幾乎是裸的KMP了——先求出新字符串的nxt數組,而後用新字符串去匹配文本串(老字符串的後面那截),若是匹配的時候文本串的指針跑到頭了,那麼如今這個模式串指針指向的字符就是合併後新字符串貢獻的第一個字符。若是文本串指針還沒跑到頭,模式串指針跑到頭了,那麼說明新字符串合併上去之後就啥都不剩了,徹底被老字符串吞併了。這兩種狀況,均可以返回模式串指針的位置。這個位置一直到新字符串末尾這段就是要新加的了。ip
另外,KMP各類寫法致使的指針加一減一的問題,微調一下就行了。字符串
快速求幾個子串的哈希值的方法,貌似NOI201六、2017連着考了兩年,其餘時候也用得很多,但我至今還沒填坑……再次留坑。扔個連接先跑了。get
#include<cstdio> #include<cstring> #include<algorithm> const int MAXN=1e6+5; int n; char a[MAXN],b[MAXN]; int nxt[MAXN]; int lena,lenb; int kmp(int st)//傳入模式串的匹配起點 { int i,j; nxt[0]=-1; for(i=1,j=-1;i<lenb;i++) { while(~j&&b[i]!=b[j+1]) j=nxt[j]; if(b[i]==b[j+1]) j++; nxt[i]=j; } // for(int x=0;x<lenb;x++) printf("%d ",nxt[x]); // puts(b); for(i=st,j=-1;i<lena;i++) { while(~j&&b[j+1]!=a[i]) j=nxt[j]; if(a[i]==b[j+1]) j++; if(j==lenb-1) return lenb; } return j+1; } int main() { //freopen("test.in","r",stdin); scanf("%d%s",&n,a); lena=strlen(a); n--; while(n--) { scanf("%s",b); lenb=strlen(b); int temp=kmp(std::max(0,lena-lenb)); // printf("%d\n",temp); for(int i=temp;i<lenb;i++) a[lena++]=b[i]; } a[lena]=0; puts(a); return 0; }
這場CF的F題據說是什麼基環樹,太難了(藉口),留坑,不補了iframe