CF600C Make Palindrome

题意:给定一个只包含小写字母的字符串,你可以修改任意位置的字符(变换为a-z中任一个)

然后重新排列字符串。现在要求用最少次数的修改得到一个回文串,若有多种方案,输出字典序最小的方案。

 

对于长度为偶数的字符串显然好说

我们只需开一个桶记录下a-z分别有多少个

偶数个的前后分别输出 个数/2次 即可

奇数个的两两匹配,分别输出前面的 个数/2+1次,输出后面的的 个数/2次 即可

 

对于长度为奇数的的字符串我们发现有一部分字符串是不输出的(被替换掉的)

我们在不输出的中 和 剩余的唯一的奇数个字符中找最小的填入序列中间即可

 

实现如下:

#include <algorithm>
#include <iostream>
#include <cmath>
#include <cstring>
#include <map>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstdlib>
using namespace std;
typedef long long ll;
inline int read()
{
    register int p(1),a(0);register char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if(ch=='-') p=-1,ch=getchar();
    while(ch>='0'&&ch<='9') a=a*10+ch-48,ch=getchar();
    return a*p;
}
const int N=200010;
char a[N],cun[N];
int n,book[30],dan[N],ge,ji,all=0,us=0,fla;
int main()
{
//    freopen("input","r",stdin);
//    freopen("output","w",stdout);
    scanf("%s",a+1);n=strlen(a+1);
    for(int i=1;i<=n;i++) book[a[i]-'a']++;
    for(int i=0;i<26;i++) if(book[i]&1) dan[++ge]=i;
    for(int i=0;i<26;i++) all+=book[i];
    if(all&1)
    {
        cun[(n>>1)+1]='a'+dan[(ge>>1)+1];
        book[dan[(ge>>1)+1]]--;ge--;
    }
    for(int i=0;i<26;i++)
    {
        for(int j=(book[i]>>1);j>=1;j--)
        {
            ++us;
            cun[n-us+1]=cun[us]='a'+i;
        }
        if(book[i]&1)
        {
            ++ji;
            if(ji<=ge)
            {
                ++us;
                cun[n-us+1]=cun[us]='a'+i;
                ge--;
            }
        }
    }
    for(int i=1;i<=n;i++) printf("%c",cun[i]);
    return 0;
}
/*

*/

 

posted @ 2018-12-07 00:51  cold_cold  阅读(216)  评论(0编辑  收藏  举报