一、题目大意
一次操作:可以将字符串S任意两个字符i,互换位置
目标字符串:形成反回文字符串,即长度为n的字符串中任意的s[i]!=s[n-i]
如果能成功,输出最小操作次数,如果不能成功,输出-1
二、解题思想
贪心
首先我们很容易的就可以发现一个特例,字符串长度为奇数的永远不可能操作成功,因为最中间的字符的回文字符永远等于他自己
其次,如果一个字母出现的次数大于n/2 ,那么也不可能操作成功,因为右边总是会出现和左边相等的情况(这个应该也不难证明)
除此之外的所有情况都可以在有限次数内操作成功。
那么操作的时候如何贪心呢?
我们首先要发现,无论怎么操作,一次操作使满足题目要求的字符对最多只能增加两个。
比如(a,a)和(b,b) 将a和b交换位置之后,这两个都将是反回文数对。我们还可以保证,我们每一次的操作都可以至少保证增加一个反回文数对,如(a,a) (b,c)将a与任何一个数对进行交换就可以使(a,a)满足条件。
思路就是如此,下面上代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
char a[N];
int cnt_pair[50];
int cnt[50];
bool cmp (int a,int b)
{
return a>b;
}
void sol()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
if(n%2)
{
cout<<"-1\n";
return ;
}
memset (cnt_pair,0,sizeof cnt_pair);
memset (cnt,0,sizeof cnt);
int res_pair=0;
int res=0;
for(int i=1;i<=n/2;i++)
{
if(a[i]==a[n-i+1])
{
cnt_pair[a[i]-97]++;
res_pair=max(res_pair,cnt_pair[a[i]-97]);
}
cnt[a[i]-97]++;
cnt[a[n-i+1]-97]++;
res=max(cnt[a[i]-97],res);
res=max(cnt[a[n-i+1]-97],res);
}
if(res>n/2)
{
cout<<"-1\n";
return ;
}
int num=0;
sort (cnt_pair,cnt_pair+26,cmp);
while(cnt_pair[0]!=0)
{
if(cnt_pair[1]!=0)
{
num++;
cnt_pair[0]--;
cnt_pair[1]--;
sort (cnt_pair,cnt_pair+26,cmp);
}
else
{
num+=cnt_pair[0];
cnt_pair[0]=0;
}
}
cout<<num<<"\n";
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T;
cin>>T;
while(T--) sol();
return 0;
}
如果还有不清楚的地方,可以评论区留言问我