题意:
给一个字符串t ,求与这个序列刚好有m个位置字符不同的由两个相同的串拼接起来的字符串 s,
要求字典序最小的答案
分析:
把字符串折半,分成0 - n/2-1 和 n/2 - n-1
dp[i][j] 表示 第i位及之后的总代价为j可不可行
从第 n/2-1 位推回第 0 位, 若dp[0][m] = 1,则存在
然后贪心对每一位从'a'试到'z',选取接下来存在解的字符
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 1005;
bool dp[MAXN][MAXN];//dp[i][j] :第i位及之后的总代价为j可不可行
int t, n, m;
char s[MAXN];
int main()
{
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &m);
scanf("%s", s);
memset(dp, 0, sizeof(dp));
dp[n/2][0] = 1;
for (int i = n/2-1; i >= 0; i--)
{
if (s[i] == s[i+n/2])
{
for (int j = 0; j <= m; j++) dp[i][j] = dp[i+1][j];//不改
for (int j = 0; j <= m-2; j++) if (dp[i+1][j]) dp[i][j+2] = 1;//改两个
}
else
{
for (int j = 0; j <= m-1; j++) if (dp[i+1][j]) dp[i][j+1] = 1;//改一个
for (int j = 0; j <= m-2; j++) if (dp[i+1][j]) dp[i][j+2] = 1;//改两个
}
}
if (!dp[0][m])
{
puts("Impossible"); continue;
}
int k = m;
for (int i = 0; i < n/2; i++)
{
for (int j = 0; j < 26; j++)
{
int p = 0;
if (s[i] != j+'a') p++;
if (s[i+n/2] != j+'a') p++;
if (dp[i+1][k-p])
{
s[i] = j + 'a';
s[i+n/2] = j + 'a';
k -= p;
break;
}
}
}
puts(s);
}
}