题目链接:https://www.dotcpp.com/oj/problem1467.html?sid=2421345&lang=1#editor
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入
第一行是一个整数N,表示接下来的字符串的长度(N < = 8000)
第二行是一个字符串,长度为N.只包含小写字母输出
如果可能,输出最少的交换次数。
否则输出Impossible样例输入
5 mamad
样例输出
3
当时没来的及做,后来看的时候考虑简单了wa了。
思路(对称位置的位置差):
首先说一下不成立的情况:
当n为偶数的时候,若存在奇数个的字母,就会不成立。
当n为奇数的时候,若奇数个的字母超过一个,就会不成立。
接下来讲一下成立的情况下最少的移动次数。
设置两个变量,i和j,分别指向字符串a的首尾。
如果a[i]==a[j],i++,j--;不做交换
如果a[i]!=a[j],从k=j-1,来寻找使得a[i]=a[k],这里又分两种情况。
1.i!=k时,说明找到了,并对字符串的字符进行交换。
2.i==k,说明这是奇字符串中的奇字符。先不做任何处理,只是加上步数(与中间位置的差值)。
这里说明一下为什么不进行交换(不做处理):
例如字符串 cdaabbc 。若对字符d交换后是 caadbbc 那么在之后的交换中会多和d交换一次。
不做处理,把之后的交换完成,最后字符d交换当前位置与中间位置的差值的次数就可。
AC代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <set> #include <stack> #include <queue> #include <vector> #include <string> #define cla(a, sum) memset(a, sum, sizeof(a)) #define rap(i, m, n) for(i=m; i<=n; i++) #define rep(i, m, n) for(i=m; i>=n; i--) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll, ll> P; const int Inf = 0x3f3f3f3f; const double eps = 1e-8; const int maxn = 1e4+5; int n; char a[maxn]; int c[30]={0}; int main() { cin>>n; scanf("%s",a+1); int i,j,k; for(i=1;i<=n;i++){ j=a[i]-'a'+1; c[j]++; } k=0; rap(i,1,26){ if(c[i]%2)k++; } if(k>=2||(n%2==0&&k==1)){//不成立 printf("Impossible"); return 0; } int sum=0; for(i=1,j=n;i<j;i++){ if(a[i]==a[j]){ j--; continue; } int ans=0; for(k=j-1;k>i;k--){ ans++; if(a[k]==a[i]){ break; } } if(k==i){//特殊情况,奇字符 sum+=n/2-i+1; continue; } sum+=ans; for(;k<j;k++){ swap(a[k],a[k+1]); } j--; } cout<<sum<<endl; return 0; }