题目链接:点击查看
题目大意:给出一个长度为 n 的回文串,问最小修改多少个字母,可以使得整个回文串可以被划分成不超过 k 个连续的回文串,并输出最终的划分方案
题目分析:n 很小,考虑多维 dp
首先预处理出 cost 函数辅助 dp 的转移,cost[ l ][ r ] 是将区间 [ l , r ] 内的字符串修改成回文串的最小花费,转移方程也比较简单 cost[ l ][ r ] = cost[ l + 1 ][ r - 1 ] + ( a[ l ] != a[ r ] ),时间复杂度是 O( n^2 )
考虑 dp[ i ][ j ] 是前 i 个位置中,划分了 j 个回文串的最小代价,dp[ i ][ j ] = dp[ k ][ i - 1 ] + cost[ k + 1 ][ i ],枚举 k 去转移就好了,时间复杂度是 O( n^3 )
转移的时候开一个数组记一下前驱,方便后续路径输出
有了前驱的分割,就可以将原字符串分割成数个互不相交的字符串了,对于每个字符串,直接贪心修改成回文即可
代码:
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=510;
string s;
int cost[N][N],dp[N][N];
pair<int,int>pre[N][N];
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.ans.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
cin>>s;
int n=s.size(),k;
s=" "+s;
scanf("%d",&k);
//cost[i][j]=cost[i+1][j-1]+(s[i]==s[j]) cost[i][j]:区间[i,j]变为回文串的代价
memset(cost,0,sizeof(cost));
for(int i=n;i>=1;i--)
for(int j=i;j<=n;j++)
cost[i][j]=cost[i+1][j-1]+(s[i]!=s[j]);
//dp[i][j]=min(dp[i][j],dp[t][j-1]+cost[t+1][i]) dp[i][j]:前i个数中分割成j个回文串的代价
memset(dp,inf,sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++)
for(int t=0;t<i;t++)//断点
if(dp[t][j-1]+cost[t+1][i]<dp[i][j])
{
dp[i][j]=dp[t][j-1]+cost[t+1][i];
pre[i][j]=make_pair(t,j-1);
}
int mmin=inf,mark=-1;
for(int i=1;i<=k;i++)
if(dp[n][i]<mmin)
mmin=dp[n][i],mark=i;
printf("%d\n",mmin);
vector<int>pos;
int pos1=n,pos2=mark;
while(pos2)
{
pos.push_back(pos1);
tie(pos1,pos2)=pre[pos1][pos2];
}
reverse(pos.begin(),pos.end());
int p=1;
for(auto it:pos)
{
string ans=s.substr(p,it-p+1);
for(int i=0;i<ans.size()/2;i++)
ans[i]=ans[ans.size()-i-1];
cout<<ans;
p=it+1;
if(p<=n)
cout<<"+";
}
return 0;
}