日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Gym 100431EWord Cover 题解:KMP上跑dp

發布時間:2025/4/14 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Gym 100431EWord Cover 题解:KMP上跑dp 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意:

?

給你一個串,問你他的每個前綴的最小重復單元,其中單元是可以重疊的,最后按順序輸出即可。比如樣例中abaabaa的最小重復單元為abaa,所以相應輸出為4。

樣例:

?

input :?abaabaababa

output:1 2 3 4 5 3 4 5 3 10 3


?

?

kmp過程就不用多說了,現在我們利用next數組的性質來對問題進行求解。


我們首先用一個ans[maxn]數組來記錄最后的答案,且我們的字符串下標從0開始,顯然,我們ans[i]的最大值為i+1,我們因此也用此值對其進行初始化。

現在我們考慮什么情況下ans[i]可以得到更小的,更小他能達到多小。


其實這個顯然可以知道第i位的ans值只能從ans[next[i]]那里獲得,這個就可以根據next數組的性質想一想就明白了,若存在更短的,到i的后面的這段就不成立了。


然后我們考慮i和next[i]位置的兩種情況:


第一種情況:i - next[i] ≤ next[i]





此時顯然就可以利用ans[next[i]]進行更新了,如果可以形成前面這段,那么一定可以形成后面那段。


第二種情況:i - next[i] > next[i]




這種情況就是此題的難點所在了,乍看之下似乎這種情況下只能放棄用ans[next[i]]來更新ans[i]了,其實不然!!!

樣例就給我們了很好的反例,因為樣例最后一位的答案是3!


我們用dp[k]來記錄最后ans是k的最大的下標,我們假設cnt = ans[next[i]],即在next[i]處的答案,然后如圖:




一個比較顯而易見的是cnt ≤ next[i]是肯定成立的,而此種假設下我們假設i - next[i] ≤ next[i],現在決定最終成敗的就只剩下dp[cnt]的具體位置了!!!


我們證明 i - dp[cnt] ≤ cnt 時的情況必然可以用cnt來更新ans[i]。

此時狀況完全如上圖所示,此時在dp[cnt]前已經得知必可由長度為cnt的串來產生,而這cnt長得串同時也肯定是從0到next[i]中長度為cnt的后綴。那么根據next數組的性質,這段串與i-cnt ~ i這段是相同的。我們又假設了?i - cnt ≤ dp[cnt] ,因此我們的i-cnt ~ i這段必然可由與形成dp[cnt]長度相同的串來產生,同時這也是其所有可能的最小答案。


最后當next[i] = -1 的時候就沒什么說的了,顯然上面說的這些都沒用了,直接就賦值給 ans[i] = i + 1,再更新一下 dp[ans[i]] = i 就可以了。


在此表達對此神作法的膜拜之情!

本弱渣的代碼如下:



#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <queue> #include <vector> #include <algorithm>using namespace std;char word[250010]; int next[250010], ans[250010], dp[250010];int main() {freopen("cover.in", "r", stdin);freopen("cover.out", "w", stdout);scanf("%s", word);int len = strlen(word), k = -1;next[0] = -1;for (int i = 1; i < len; i++) { // KMP構造next數組過程while (k != -1 && word[i] != word[k + 1]) k = next[k];if (word[i] == word[k + 1]) k++;next[i] = k;}for (int i = 0; i < len; i++) {ans[i] = i + 1; //首先賦值最大的可能值i+1if (next[i] != -1) {int cnt = ans[next[i]];if (i - next[i] <= next[i] || i - dp[cnt] <= cnt) {ans[i] = cnt;}}dp[ans[i]] = i; //用ans[i]去更新dp[ans[i]]}for (int i = 0; i < len - 1; i++) printf("%d ", ans[i]); printf("%d\n", ans[len - 1]);return 0; }



?

轉載于:https://www.cnblogs.com/ScratchingBear/p/5345825.html

總結

以上是生活随笔為你收集整理的Gym 100431EWord Cover 题解:KMP上跑dp的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。