CF1131E String Multiplication 题解
关于发现调了两个小时的题被学长场切了
一些结论
翻一下题面给出的“乘法”,其实就是把一个字符串重复插入到另一个字符串中
首先可以发现,除了 \(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;
}