CodeForces - 137D Palindromes(dp+路径输出)

题目链接:点击查看

题目大意:给出一个长度为 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;
}

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:设计师小姐姐 返回首页