题意:给定一个只包含小写字母的字符串,你可以修改任意位置的字符(变换为a-z中任一个),然后重新排列字符串。现在要求用最少次数的修改得到一个回文串,若有多种方案,输出字典序最小的方案。
思路:找出并记录所有字母的出现次数num[],若num[i] & 1说明该字母不能对称放置,这时有两种方案——1,需要把其它字母改为当前字母;2,把该字母改为其它字母。为了得到最小字典序,我们贪心的选择将字典序大的字母改为字典序小的字母,按照这样的思维模拟即可。
注意:串长度len & 1时的处理。
AC代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#define INF 0x3f3f3f
#define eps 1e-8
#define MAXN (200000+10)
#define MAXM (100000)
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%.2lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while(a--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 1000000007
#define LL long long
#define lson o<<1, l, mid
#define rson o<<1|1, mid+1, r
#define ll o<<1
#define rr o<<1|1
using namespace std;
char str[MAXN]; int num[30];
bool mark[30];
int main()
{
Rs(str); CLR(num, 0);
int len = strlen(str);
for(int i = 0; i < len; i++)
num[str[i]-'a']++;
CLR(mark, false); int cnt = 0;
for(int i = 0; i < 26; i++)
if(num[i] & 1)
mark[i] = true, cnt++;
char mid; int use = 0;
if(len & 1)
{
cnt--;
for(int i = 0; i <= 25; i++)
{
if(mark[i])
use++;
if(use > cnt / 2)
{
mid = 'a' + i;
mark[i] = false;
break;
}
}
}
bool flag = false; use = 0;
for(int i = 0; i <= 25; i++)
{
if(mark[i])
{
if(flag)
num[i]--;
else
num[i]++;
use++;
}
if(use == cnt / 2)
flag = true;
}
int F = 0, B = len-1;
for(int i = 0; i < 26; i++)
{
for(int j = F; j < F + num[i] / 2; j++)
str[j] = 'a' + i;
F += num[i] / 2;
for(int j = B; j > B - num[i] / 2; j--)
str[j] = 'a' + i;
B -= num[i] / 2;
}
if(len & 1)
str[len / 2] = mid;
Ps(str);
return 0;
}