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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

【CF594E】Cutting the Line 【贪心】【Lyndon Word】【扩展kmp】

發布時間:2023/12/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【CF594E】Cutting the Line 【贪心】【Lyndon Word】【扩展kmp】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

傳送門

題意:給一個字符串SSS和正整數kkk,將SSS分成最多kkk段,每段不變或翻轉,使得最后的字典序最小。

∣S∣≤5×106|S|\leq5\times10^6S5×106

發現不翻轉可以看成拆成若干單字符分別翻轉,所以先分析一下必須翻轉的情況

把原串翻轉記為SRS^RSR,然后我們要求的是不斷剪掉SRS^RSR的后綴然后依次拼起來

這樣最終串的第一段是SRS^RSR的一個后綴,所以最終串的開頭一定有SRS^RSR的最小后綴,但不一定是最小后綴作為第一段,因為最小后綴可能會在前面作為非后綴出現

顯然這個“最小后綴”是Lyndon分解后的最后一段,記為sss 我們希望開頭的sss盡量多

那么SRS^RSR可表示為a1s+t1+a2s+t2+...+ans+tn+asa_1s+t_1+a_2s+t_2+...+a_ns+t_n+asa1?s+t1?+a2?s+t2?+...+an?s+tn?+as(和Lyndon分解沒有關系)

首先可以一刀把asasas砍掉,然后找到a1~ana_1\sim a_na1?an?中最大的砍下來 發現這第二段是砍掉asasas后的最小后綴,相當于是下一輪的第一段

整理一下,對SRS^RSR進行Lyndon分解并合并相等段,這個Duval的時候魔改一下就可以了

然后依次砍掉最后一段并讓k?1k-1k?1

注意我們假設了必須翻轉,如果我們發現有連續一段的長度為111的串,相當于這一段不翻轉,只需要一步

這個流程需要砍掉兩段(只是后面一段和下一步的第一段重合了),所以需要k>2k>2k>2

完了之后有k≤2k \leq 2k2,如果剩下的只有一段直接大力討論掉

如果k=1k=1k=1,SSSSRS^RSR取個min?\minmin即可

如果k=2k=2k=2,相當于分兩段大力討論 注意是針對原串

  • 前面后面都不翻 就是原串
  • 只翻后面
  • 我們考慮找到最優的位置

    從左到右循環,設當前最優位置為cutcutcut,需要更新的位置為iii 注意cut<icut<icut<i


    (橙色部分為反串,TTTSRS^RSR)

    我們希望比較兩個串的大小 所以從cutcutcut開始找到第一個不同的位置比較大小

    首先求出Scut~i?1S_{cut\sim i-1}Scuti?1?TTT的最長公共前綴,可以先跑一個exKMP,求出SSScutcutcut開始的后綴與TTT的最長公共前綴后和i?cuti-cuti?cutmin?\minmin

    如果把藍色部分頂滿了,再加上后面的部分

    TTTi?cuti-cuti?cut開始的后綴與TTT的最長公共前綴與n?i+1n-i+1n?i+1min?\minmin

    然后討論一下找到第一個不同的字符比較大小即可

  • 翻前面,后面不管
  • 繼續從SRS^RSR的結尾截后綴,設截取的后綴為TTT

    考慮分解后的最后一個Lyndon串sss,TTT一定以sss開頭,也以sss結尾

    根據意識流,TTT一定不會只取一個分解后的LW的一部分,也不會把兩個相等的LW隔開

    TTT開始的第一段為s′s's,所以ssss′s's的前綴

    然后有若干個s′s's接在后面,這些s′s's后的第一個設為ttt

    根據Lyndon分解的定義,t≤s′t \leq s'ts。而如果t<s′t <s't<s,那么從ttt開始截取后綴會比TTT小,與定義矛盾

    所以TTT一定是s′+s′+...+s′+s+s+...+ss'+s'+...+s'+s+s+...+ss+s+...+s+s+s+...+s的形式

    把上面剩下的 Lyndon分解合并相等段 的倒數第二段提出來,如果sss是它的前綴,說明倒數第二段是s′s's,此時分類討論翻后面兩段或者只翻最后一段;如果不是說明s′s's不存在,只能翻最后一段

    第二段和反串取min?\minmin接在后面

    復雜度O(n)O(n)O(n)

    如果用std::string的話,要注意A=A+B和A+=B復雜度不同……

    #include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <string> #include <algorithm> #define MAXN 10000005 using namespace std; string s,t,ts,ans; int pos[MAXN],len[MAXN],tot; inline string reverse(string s) {string t;t.resize(s.size());int n=s.size();for (int i=0;i<n;i++) t[n-i-1]=s[i];return t; } void Duval(const string& s) {int n=s.size();for (int i=0;i<n;){int j=i,k=i+1;while (s[j]<=s[k]) {if (s[j]==s[k]) ++j;else j=i; ++k;}len[++tot]=k-j;while (i<=j){pos[tot]=i+k-j-1;i+=k-j;}} } int p[MAXN]; void Exkmp(const string& s) {int n=s.size();int mid=0,mx=0;p[0]=n;for (int i=1;i<n;i++){if (i<=mx) p[i]=min(p[i-mid],mx-i+1);while (s[i+p[i]]==s[p[i]]) ++p[i];if (i+p[i]-1>mx) mid=i,mx=i+p[i]-1;} } int main() {ios::sync_with_stdio(false);cin>>s;t=reverse(s);int k;cin>>k;if (k==1) return cout<<min(s,t),0;Duval(t);pos[0]=-1;while (k>2&&tot){if (len[tot]==1){while (tot&&len[tot]==1) ans+=t.substr(pos[tot-1]+1,pos[tot]-pos[tot-1]),--tot;--k;}else ans+=t.substr(pos[tot-1]+1,pos[tot]-pos[tot-1]),--k,--tot;}if (tot==0) return cout<<ans,0;if (tot==1){string tmp=t.substr(0,pos[1]+1);tmp=min(tmp,reverse(tmp));cout<<ans+tmp;return 0;}s=reverse(t=t.substr(0,pos[tot]+1));ts=t+"#"+s;Exkmp(ts);string tmp=min(s,t);int cut=0,n=s.size();for (int i=1;i<n;i++){int cl=min(i-cut,p[n+1+cut]);if (cut+cl==i) cl+=p[cl];cl=min(cl,n-cut);if ((cl<i-cut? s[cut+cl]:t[cut+cl-i])<t[cl]) cut=i;}tmp=min(tmp,s.substr(0,cut)+t.substr(0,n-cut));string las=t.substr(pos[tot-1]+1,len[tot]);string lass=t.substr(pos[tot-2]+1,len[tot]);int st=pos[tot-1]+1;string tt=t.substr(st,n-st);string res=t.substr(0,n-tt.size());tt+=min(res,reverse(res));tmp=min(tmp,tt);if (las==lass){st=pos[tot-2]+1;tt=t.substr(st,n-st);res=t.substr(0,n-tt.size());tt=tt+min(res,reverse(res));tmp=min(tmp,tt);}cout<<ans+tmp;return 0; }

    總結

    以上是生活随笔為你收集整理的【CF594E】Cutting the Line 【贪心】【Lyndon Word】【扩展kmp】的全部內容,希望文章能夠幫你解決所遇到的問題。

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