2018.1.22【CodeForces - 600C】解題報告(貪心,字符串)

C. Make Palindrome
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

A string is called palindrome if it reads the same from left to right and from right to left. For example "kazak", "oo", "r" and "mikhailrubinchikkihcniburliahkim" are palindroms, but strings "abb" and "ij" are not.

You are given string s consisting of lowercase Latin letters. At once you can choose any position in the string and change letter in that position to any other lowercase letter. So after each changing the length of the string doesn't change. At first you can change some letters in s. Then you can permute the order of letters as you want. Permutation doesn't count as changes.

You should obtain palindrome with the minimal number of changes. If there are several ways to do that you should get the lexicographically (alphabetically) smallest palindrome. So firstly you should minimize the number of changes and then minimize the palindrome lexicographically.

Input

The only line contains string s (1 ≤ |s| ≤ 2·105) consisting of only lowercase Latin letters.

Output

Print the lexicographically smallest palindrome that can be obtained with the minimal number of changes.

Examples
input
aabc
output
abba
input
aabcd
output
abcba

【題目大意】

任意輸入一串字符,要求輸出改動次數最少(移動交換位置不算做改動)且字典序最小的迴文串。

【解題思路】

貪心的想法還是比較直觀的。由於移動交換位置不算改動。貪心的從兩端對稱輸出典序最小的字母,如果該字母出現次數位奇數,則從字典序最大的字母開始搜索,直至找到第一個出現個數也爲奇數的字母(當然也是最大的),大字母的個數-1,小字母個數+1(即用小替換大),偶數個數會調整全部字母出現次數爲偶數然後結束,奇數個數的話則需要額外判斷,如果搜索到的字母和原字母相同,則說明該字母是中間字母(不一定該字母都在中間!)

易錯:把中間字母單獨提出來然後相鄰的放到中間。比如aabbhhwwhwwhhbbaa輸入本應該原樣輸出,但是卻輸出了aabbwwhhhhhwwbbaa,這樣會使字典序增大,需要對中間字母特殊處理(正常左右兩端輸出,只不過最後留一個在中間打印就行。)

【解題代碼】

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define maxn 200100
using namespace std;
char s[maxn];
char outs[maxn];
//int alpha[26];
bool mark[26];
struct node
{
	char letter;
	int times;
}alpha[26];
bool cmp(struct node n1,struct node n2)
{
	return n1.letter>n2.letter;
}
bool cmp1(struct node n1,struct node n2)
{
	return n1.letter<n2.letter;
}
void odd(int len)
{
//	printf("in odd\n");
	for(int i=0;i<len;i++)
	{
		alpha[s[i]-97].times++;
	}
	sort(alpha,alpha+26,cmp);
//	for(int i=0;i<26;i++)
//	{
//		printf("%d  %c %d\n",i,alpha[i].letter,alpha[i].times);
//	}

	int point=0,target=0;
	for(int i=0;i<26;i++)
	{
		if(!(alpha[i].times%2)) continue;
		else
		{
			target=i;
			int j;
			for(j=target,point=0;j<26;j++)
			{
				if(!(alpha[j].times%2)) continue;
				else point=j;
			}
			if(point==0) break;
			else
			{
				alpha[point].times++;
				alpha[target].times--;
			}
		}
	}
//	for(int i=0;i<26;i++)
//	{
//		printf("%d  %c %d\n",i,alpha[i].letter,alpha[i].times);
//	}
	char c=alpha[target].letter;
	char t=alpha[target].times;
//	printf("target=%c\n",c);
//	target 中間單值
	int count=0;
	int leftlen=len-alpha[target].times;
	sort(alpha,alpha+26,cmp1);
//	printf("now len=%d\n",leftlen);
	for(int i=0;count<(len-1)/2;i++)
	{
		if(alpha[i].letter==c) 
			for(int j=0;j<(alpha[i].times-1)/2;j++)
				outs[count++]=alpha[i].letter;
		else for(int j=0;j<alpha[i].times/2;j++)
				outs[count++]=alpha[i].letter;
	}
	int i;
	for(i=0;i<count;i++)
	{
		printf("%c",outs[i]);
	}
	printf("%c",c);
	for(i=count-1;i>=0;i--)
	{
		printf("%c",outs[i]);
	}
	printf("\n");
}
void even(int len)
{
//	printf("in even\n");
	for(int i=0;i<len;i++)
	{
		alpha[s[i]-97].times++;
	}
	sort(alpha,alpha+26,cmp);
//	for(int i=0;i<26;i++)
//	{
//		printf("%d  %c %d\n",i,alpha[i].letter,alpha[i].times);
//	}

	int point=0,target=0;
	for(int i=0;i<26;i++)
	{
//				if(i==25 ) printf("YOO\n");
		if(!(alpha[i].times%2)) continue;
		else
		{
			target=i;
			int j;
			for(j=target,point=0;j<26;j++)
			{
				if(!(alpha[j].times%2)) continue;
				else point=j;
			}
			if(point==0) break;
			else
			{
				alpha[point].times++;
				alpha[target].times--;
			}
		}
	}
//	char c=alpha[target].letter;
//	char t=alpha[target].times;
//	printf("target=%c\n",c);
//	//target 中間單值
	int count=0;
//	int leftlen=len-alpha[target].times;
	sort(alpha,alpha+26,cmp1);
//	printf("now len=%d\n",leftlen);
	for(int i=0;count<len/2;i++)
	{
		for(int j=0;j<alpha[i].times/2;j++)
			outs[count++]=alpha[i].letter;
	}
	int i;
	for(i=0;i<count;i++)
	{
		printf("%c",outs[i]);
	}
	for(i=count-1;i>=0;i--)
	{
		printf("%c",outs[i]);
	}
	printf("\n");
}
int main()
{
//			freopen("in.txt", "r", stdin);//其實in.txt是可以修改成其他名字的  比如“輸入.txt”,都是可以的,這裏只是爲了方便起見,下同; 
//    freopen("outmy.txt", "w", stdout);
	while(~scanf("%s",s))
	{
		memset(alpha,0,sizeof(alpha));
		for(int i=0;i<26;i++)
		{
			alpha[i].letter='a'+i;
			alpha[i].times=0;
		}
		int len=strlen(s);
		if(len%2)//Odd
			odd(len);
		else even(len); 
	}
	return 0;
}


【收穫與反思】

(第一次寫貪心,由於開始理解有偏差,改了很多次,代碼也很醜陋= =而且太冗長= =,好在最後AC了,需要後面再優化下。)

發佈了40 篇原創文章 · 獲贊 1 · 訪問量 6265
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章