传送门 https://www.luogu.com.cn/problem/P5041

题目描述
所谓回文串,就是对于给定的字符串,正着读和反着读都一样,比如ABCBA就是一个回文串,ABCAB则不是。我们的目标是对于任意输入的字符串,不断将第i个字符和第i+1个字符交换,使得该串最终变为回文串。求最少交换次数。

输入格式
一个由大写字母字母组成的字符串。

输出格式
若能经过有限次操作能将原串变为回文串,则输出最少操作次数;否则输出-1。

考虑贪心,从左往右算

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream> 
#include <vector>
#define int long long 
using namespace std;

const int maxn=1e6+10;
char ch[maxn];
int a[maxn],ans[maxn],s[maxn],b[maxn],vis[maxn],viss[maxn],len,cal;
vector<int>q[30];
int sum;
inline void init(){
   
	scanf("%s",ch+1);
	len=strlen(ch+1);
	cal=0;	
	for(int i=1;i<=len;i++){
   
		a[i]=(int)(ch[i]-'A')+1;
		s[a[i]]++;
		q[a[i]].push_back(i);
	}
	for(int i=1;i<=len;i++){
   
		int zhn=(int)(ch[i]-'A')+1;
		if(!vis[zhn]){
   
			vis[zhn]=1;
			if(s[zhn]&1)cal++; 
		}
	}
	return ;
}
void solve(int l,int r){
   //逆序对 
	if(l==r)return ;
	int mid=(l+r)>>1;
    solve(l,mid);solve(mid+1,r);
    int midd=mid+1,ll=l;
    for(int i=l;i<=r;i++){
   
	  if(midd>r||ll<=mid&&ans[ll]<ans[midd]) b[i]=ans[ll++];
	  else sum+=mid-ll+1,b[i]=ans[midd++];
	} 
	for(int i=l;i<=r;i++) ans[i]=b[i];
}
main(){
   
	
	init();
	
	if(cal>=2) printf("-1");
	else if(len%2==0&&cal) printf("-1");
	else{
   
		if(len&1){
   
			for(int i=1;i<=26;i++){
   
				if(q[i].size()&1){
   
					int lgr=q[i][q[i].size()/2];
					ans[len/2+1]=lgr;
					viss[lgr]=1;
				}
			}	
		}
		int l=1,r=len;
		int pp=1;
		while(pp<=len){
   
			if(viss[pp]){
   
				pp++;
				continue;
			}
			if(pp>len||l>r) break;
			ans[l]=pp;
			viss[pp]=1;
			l++;
			pp++;
			int lgr=q[a[pp-1]][q[a[pp-1]].size()-1];
			ans[r]=lgr;
			viss[lgr]=1;
			r--;
			q[a[pp-1]].erase(q[a[pp-1]].end()-1);
		}
	solve(1,len);
	printf("%lld",sum);
	}
	return 0;
}