Codeforces 137D - Palindromes(区间DP)

D. Palindromes

time limit per test 2 seconds
memory limit per test 256 megabytes
input standard input
output standard output
Friday is Polycarpus’ favourite day of the week. Not because it is followed by the weekend, but because the lessons on Friday are 2 IT lessons, 2 math lessons and 2 literature lessons. Of course, Polycarpus has prepared to all of them, unlike his buddy Innocentius. Innocentius spent all evening playing his favourite game Fur2 and didn’t have enough time to do the literature task. As Innocentius didn’t want to get an F, he decided to do the task and read the book called “Storm and Calm” during the IT and Math lessons (he never used to have problems with these subjects). When the IT teacher Mr. Watkins saw this, he decided to give Innocentius another task so that the boy concentrated more on the lesson and less — on the staff that has nothing to do with IT.

Mr. Watkins said that a palindrome is a string that can be read the same way in either direction, from the left to the right and from the right to the left. A concatenation of strings a, b is a string ab that results from consecutive adding of string b to string a. Of course, Innocentius knew it all but the task was much harder than he could have imagined. Mr. Watkins asked change in the “Storm and Calm” the minimum number of characters so that the text of the book would also be a concatenation of no more than k palindromes. Innocentius can’t complete the task and therefore asks you to help him.

Input

The first input line contains a non-empty string s which is the text of “Storm and Calm” (without spaces). The length of the string s does not exceed 500 characters. String s consists of uppercase and lowercase Latin letters. The second line contains a single number k (1 ≤ k ≤ |s|, where |s| represents the length of the string s).

Output

Print on the first line the minimum number of changes that Innocentius will have to make. Print on the second line the string consisting of no more than k palindromes. Each palindrome should be non-empty and consist of uppercase and lowercase Latin letters. Use the character “+” (ASCII-code 43) to separate consecutive palindromes. If there exist several solutions, print any of them.

The letters’ case does matter, that is an uppercase letter is not considered equivalent to the corresponding lowercase letter.

Examples
input
abacaba
1
output
0
abacaba
inputCopy
abdcaba
2
output
1
abdcdba
inputCopy
abdcaba
5
output
0
a+b+d+c+aba
input
abacababababbcbabcd
3
output
1
abacaba+babab+bcbabcb

题目大意:

输入一个字符串和一个K值,输出将这个字符串拆成最多k个回文串的最小操作数,第二行输出修改后的回文串,有+分割。

解题思路:

开一个cost数组,预处理 i - j 区间改成回文串的最小操作数,状态转移:
cost[i][j] = cost[i + 1][j - 1] + (a[i] != a[j])
处理完后再处理一下dp i j,表示将前 j 个字符分割成 i 个部分最少需要多少操作,状态转移:
dp[i][j] = min(dp[i - 1][l] + cost[l + 1][j], dp[i][j])
之后就是分割路径了,设一个w数组表示分割点,
dp[i - 1][j] != inf && dp[i][lt] == dp[i - 1][j] + cost[j + 1][lt]
如果这个条件满足,则证明刚好从j + 1这个点分开,w存储的是分割点的下一个位置,然后根据w里存的值来修改字符串,修改好后按照w存的点输出 + 即可。

Code:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
const int mod = 1e9 + 7;
const int N = 550;
const int inf = 0x3f3f3f3f;
typedef long long ll;
int cost[N][N], dp[N][N];
int w[N];
int main()
{
	int k;
	char a[N];
	cin >> a + 1 >> k;
	int n = strlen(a + 1);
	memset(cost, 0, sizeof cost);
	for (int i = 1; i <= n; i ++)//预处理区间修改最小值
	  for (int j = 1; j <= i; j ++)
	    cost[j][i] = cost[j + 1][i - 1] + (a[i] != a[j]);
	memset(dp, 0x3f, sizeof dp);
	dp[0][0] = 0;
	for (int i = 1; i <= k; i ++)//前j个点分成i份最小操作数
	{
		for (int j = i; j <= n; j ++)
		  for (int l = i - 1; l <= j; l ++)
		    if (dp[i - 1][l] != inf)
			  dp[i][j] = min(dp[i - 1][l] + cost[l + 1][j], dp[i][j]);
	}
	cout << dp[k][n] << endl;
	int cnt = 0, lt = n;
	for (int i = k; i >= 1; i --)//处理分割位置
	{
		for (int j = 1; j <= n; j ++)
		{
			if (dp[i - 1][j] != inf && dp[i][lt] == dp[i - 1][j] + cost[j + 1][lt])
			{
				w[i] = j + 1;
				lt = j;
				break;
			}
		}
	}
	w[k + 1] = n + 1;
	w[1] = 1;
	cnt = 1;
	for (int i = 1; i <= k + 1; i ++)//去重
	  if (w[i - 1] != w[i])
	    w[cnt++] = w[i];
	cnt -= 2;
	w[cnt + 1] = n + 1;
	for (int i = 1; i <= cnt; i ++)
	{
		int u = w[i], v = w[i + 1] - 1;//根据分好的点修改字符串
		while (u < v)
		{
			a[v] = a[u];
			u++, v--;
		}
	}
	cnt = 2;
	for (int i = 1; i <= n; i ++)
	{
		cout << a[i];
		if (i == w[cnt] - 1)
		{
			if (w[cnt] != n + 1)  cout << '+';
			cnt ++;
		}
	}
	cout << endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/aezakmias/article/details/107605618