國慶七天樂——第七天
20171007
【字符串算法】
- 模式匹配----kmp
定義:next[i+1]是最大的j+1使得p[0~j]是p[0~i]的後綴
通過這個next數組來跳過某些冗余計算
作用:當模式串p的長度為j的前綴是長度為i前綴的後綴時,若文本串在i+1的位置失配,則指針可跳到j繼續嘗試與j+1位置匹配
如何求next指針
假設已求得前i個next,要求next[i+1]
設next[i]=j
若p[j]!=p[i]則使j=next[j]
若p[i]==p[j](或j出界)則next[i+1]=j+1(或0)
【復雜度】
可以證明或者從代碼中簡單地看出,kmp算法復雜度是O(n+m)
簡單匹配當不match的時候要回溯
Kmp算法只需要每次不匹配的時候跳一次next即可
復雜度降到了線性。
證明:
KMP 算法的時間復雜度由預處理和匹配兩部分組成
外層的 i 循環和內層的 j 循環是完全獨立的,時間復雜度可以單獨計算
i循環的時間復雜度明顯是 O(N)
j本身有加有減,但易知其下降的總次數不會超過增加的總次數( j 每次固定+1,但每次至少-1)
j 每次增加都隨i加1,故增加的總量為N,j下降的次數不會超過N
故 j 循環的時間復雜度也是 O(N)
總過程的時間復雜度為 O(N) 總時間復雜度是 O(N + M)
*********************例題*****************************
1.Poj2406
題意:給一個字符串,問字符串中有多少個循環
根據kmp中next數組的性質來求解
Next數組性質: p[0~j]是p[0~i]的後綴,A=B
顯然x=z,y=w
又因為y=z
所以x=y=z=w
……
由數學歸納法,得x為原串的最小循環節
2.NOI2014
題意:給定一個長為L的字符串(L<=100W),求一個num數組,num[i]表示長度為i的前綴中字符串S’的數量,其中S‘既是該前綴的前綴也是該前綴的後綴,且|S‘|*2<=i
Kmp變式
定義由i=next[i]轉移到-1的步數是dep[i]
從i跳到j<=i/2的位置,num[i]=dep[j] 想想為什麽?
然後就兩次kmp就好了
【字符串哈希】
字符串具有離散性強,長度大等特點,不易比較
如果給每個字符串一個數值做標簽,比較的時候直接比較這個標簽就能確定字符串是否匹配。
這個標簽就是字符串HASH函數
常用的HASH函數(BKDR HASH):
也有其他花式HASH函數,在此不一一例舉
參考資料: http://blog.csdn.net/djinglan/article/details/8812934
代碼:
常用的seed值: 31、131、1313、13131、131313..
例如我們取x=131
求串s=pekinguniversity 的hash[s]
Hash[s]=p*131^15+e*131^14+…+y*131^0
那麽如果要在文本中找到串s,只用維護一個長度為16的子串的hash值並與hash(s)比較即可
維護長度為l的子串的hash值
設已知hash[s[ i-l+1 ~ i ]]=h,要求h1=hash[s[ i-l ~ i+1 ]]
h1=(h-s[i-l+1]*seed^(l-1))*seed+s[i+1]*seed^0
******************例題*******************************
- 1. 口吃的外星人
題意:有一個外星人說的話裏包含很多重復的字符串,如ababa包含兩個aba,給定這個外星人說的一句話,找出至少出現m詞的最長字符串,字符串長度4e4
解法:二分答案L,判斷長度L的子串最多出現多少次
維護長度L的子串hash,若某hash值出現m次則有解
復雜度O(n log n)
【回文串manacher】
對稱軸可能是字符串中的一個位置或者一個間隙
避免重復操作?
把間隙變成字符!
aba —> #a#b#a#
abba —> #a#b#b#a#
Def: r[i]->以i為對稱軸的最長匹配半徑
e.g.
0 1 2 3 4 5 6
# a # b # a #
r: 0 1 0 3 0 1 0
r恰好是最長回文串的長度
(因為加了#的緣故,所以字符串長度變成了兩倍,而r是枚舉最長子串的半徑,所以r最長就是回文子串最長)
先定義兩個指針
Pos:一個回文串的對稱軸
Max_r:max(pos+r[pos])
情況1:i<max_r,取j為i關於pos的對稱位置
當r[j]+i>max_r時,i~max_r的一段必然可以匹配成回文串
而max_r+1的位置開始需要逐位匹配
Max_r=i+r[i],pos=I
情況2:i<max_r,取j為i關於pos的對稱位置
r[j]+i<=max_r
r[i]=r[j]
情況3:i>=max_r
從i開始往右逐位匹配,max_r=r[i]+i
***********************例題*************************
題目大意:
就是現在給出一個長度為 n 的字符串(1 <= n <= 10^6)和一個正整數K(1 <= K <= 10^12)
對於給出的長度為n的字符串如果其回文串的數量比K少則輸出-1, 否則輸出所有回文串中長度為奇數的最長的前K個回文串的長度的乘積, 結果對於19930726取模輸出
解法:
首先可以用manacher算法確定每個位置的回文半徑, 由於這裏只需要長度是奇數, 所以不需要再原來的字符串的相鄰兩個字符之間插入未出現的字符, 直接在首尾添加好不同字符之後盤一遍manacher算法, 對於位置i為中心的回文半徑R[i], 用dp[i]來表示相鄰長度的回文串的數量差分(其實就是一個常用的前綴和技巧, 因為這裏每次更新[1, R[i]]這個區間 + 1, 而只在所有更新完畢之後才查詢所以沒有必要使用樹狀數組, 直接根據每次更新的時候dp[1]++, dp[R[i] + 1]--, 最後後dp[1~i]的和就是最終ans[i]的值, 即長度為2*i - 1的回文串的數量,然後用快速冪就可以了
【考試2】
T1字符串
Manacher板子
T2動態規劃
狀態壓縮dp,估計深搜廣搜優化一下也能過
F(I,j,p)表示第i時間段選擇課程為j,此時combo為p的最大收獲量
Add是j狀態i時刻能獲得的收獲
當狀態與選課吻合時
F(I,j,p)=max{f(I-1,k,p-1)}+add (1<=p<=10)
當選課與狀態不吻合時
f(I,j,0)=max{f(i-1,k,p)+p*(p-1)/2}+add (0<=p<=10)
T3圖論
最小生成樹加dfs加貪心
因為邊是以億為單位的1e8數量級,而且不同邊價格不同,所以n-1條邊結果一定最優,所以買邊和訪問是分開的兩個問題。
先最小生成樹建邊,把花費*1e8加入答案。
Dfs計算訪問一顆子樹的時間T[i]和每顆子樹的費用和sum[i]
貪心,策略類似於國王遊戲
由於限制訪問次數,訪問子樹時必定先遍歷完一顆子樹再去訪問另一顆
那麽當存在兩顆子樹時,設T0,sum0,T1,sum1
若先訪問0,則1的等待時間和等待花銷已知,為t0*sum1
同理若先訪問1,則0的花銷為t1*sum0
當t0/sum0<t1/sum1時,先訪問t0更優
對每個點的子樹的ti/sumi排序
順序訪問子樹,轉化為子問題,此題得解。
國慶七天樂——第七天