CF1131E String Multiplication 題解
阿新 • • 發佈:2021-11-08
關於發現調了兩個小時的題被學長場切了
一些結論
翻一下題面給出的“乘法”,其實就是把一個字串重複插入到另一個字串中
首先可以發現,除了 \(p_n\) ,其他字串至多隻有1的權值,所以我們先考慮 \(p_n\)
可以想到,相乘只會讓字串字首權值或者字尾權值變大,也就是說相乘後會有變化的地方只有字首和字尾
進一步可以想到,如果該字串並非整個串都是同一個字元,那麼該字串首位相連之後就不會再變化了
所以考慮整個字串字元相同的時候,就直接把 \(p_n\) 按題意乘到 \(p_{n-1}\) 裡面,再按一般的方法處理
注:圖片中從上到下插入,根據題意實際上是從下到上乘
做法
- 倒序考慮這個式子,首先處理 \(p_n\)
- 如果這個字串並不是整個串都相等的,就考慮直接在其中找一個合法子序列
- 然後考慮前後綴,如果前後綴是同一個字元,那麼就在前面的字串中找到一個一樣的字元,用來把前後綴接在一起,前後綴不相同時也是一樣
- 如果整個串都相同,那麼就把它和上一個串合併(因為如果整個串都相同,其實這個串性質和一個字元差不多)
- 而對於遞迴到的串,也和上面的法則一樣處理——連線前後綴、合併,用一個簡單的乘法原理就能統計答案了
#include<iostream> #include<cstdio> #include<vector> #include<cstring> #define ll long long using namespace std; char c[100001]; vector<char>ch[100100]; ll n,len,a[100001],ans(1),m; bool pool[100001][30]; void dfs(ll dep,char sam='\0'){ if(dep<1)return ; ll g=ch[dep].size(); for(ll i=1;i<=g;i++)a[i]=0; for(ll i=0;i<=ch[dep].size();i++)c[i+1]=ch[dep][i]; for(ll i=1;i<=g;i++){ if(sam=='\0'||c[i]==sam){ ll j=i; for("lmh qs rrd";j<=g;j++) if(c[i]!=c[j])break; j--; for(ll k=i;k<=j;k++)a[k]=j-i+1; ans=max(ans,(j-i+1)+len*(j-i+2)); i=j; } } if(sam=='\0')sam=c[1]; if(a[1]!=g){ if(c[1]==c[g]){ // ans=max(ans,(a[1]+a[g])+(a[1]+a[g]+2)*len); for(ll i=1;i<dep;i++) for(ll j=0;j<=ch[i].size();j++) if(ch[i][j]==sam)ans=max((a[1]+a[g])+(a[1]+a[g]+2)*len+1,ans); } else { for(ll i=1;i<dep;i++) for(ll j=0;j<=ch[i].size();j++) if(ch[i][j]==sam)ans=max(ans,1+(a[1]+1)*len+a[1]); for(ll i=1;i<dep;i++) for(ll j=0;j<=ch[i].size();j++) if(ch[i][j]==sam)ans=max(ans,1+a[g]+(a[g]+1)*len); } } else { len=g+(g+1)*len; dfs(dep-1,c[1]); } } int main(){ scanf("%lld",&n); for(ll i=1;i<=n;i++){ cin>>c+1; m=strlen(c+1); for(ll j=1;j<=m;j++) ch[i].push_back(c[j]); } dfs(n); cout<<ans; return 0; }