C. Make Palindrome(构造最省最小回文串)

https://codeforces.com/problemset/problem/600/C

题意翻译

给出一个由小写字母组成的字符串 ss。首先你可以改变 ss 中任意多个字母。然后你可以改变 ss 中各个字母的排列顺序。问如果要将 ss 变成回文串至少要改变多少个字母?(改变排列顺序不算改变字母)

输入输出样例

输入 #1复制

aabc

输出 #1复制

abba

输入 #2复制

aabcd

输出 #2复制

abcba

思路:假如有t个奇数个数的部分,那么能凑成回文串的变化次数最小是t/2下取整。比如奇 奇 奇 奇,互相给一个就能变成回文。

比如奇 奇 奇 剩下一个奇数不用动。所以整个是t/2下取整。

然后贪心,肯定是把字典序大的字符变成小的最划算,双指针模拟一下找到两个奇数的一小一大互相换。

最后输出就好了。

第一次碰到map的倒序遍历要用新的迭代器,还要rbegin(),rend()

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5;
typedef long long LL;
map<LL,LL>map1;
map<LL,LL>:: iterator it;
map<LL,LL>:: reverse_iterator rit;//倒序遍历的时候注意 
int main(void)
{
  string a,b;b="#";
  cin>>a;LL len=a.length();
  b+=a;
  for(LL i=1;i<=len;i++){
  	map1[b[i]-'a']++;
  }
  LL i=0;LL j=25;
  while(i<j)
  {
  	 while(i<j&&!(map1[i]&1)) i++;
  	 while(i<j&&!(map1[j]&1)) j--;
  	 map1[i]++;map1[j]--;
  }
  for(it=map1.begin();it!=map1.end();it++){
  	for(LL i=1;i<=(it->second)/2;i++){
  		cout<<char(it->first+'a');	
	}
  }
  
  for(it=map1.begin();it!=map1.end();it++){
  	if((it->second)&1) cout<<char(it->first+'a');
  }
  for(rit=map1.rbegin();rit!=map1.rend();rit++){
  	for(LL i=1;i<=(rit->second)/2;i++){
  		cout<<char(rit->first+'a');
	}
  }
  cout<<endl;
return 0;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/108551683