【原题】
A palindrome is a string of symbols that is equal to itself when reversed. Given an input string, not necessarily a palindrome, compute the number of swaps necessary to transform the string into a palindrome. By swap we
mean reversing the order of two adjacent symbols. For example, the string "mamad" may be transformed into the palindrome "madam" with 3 swaps:
- swap "ad" to yield "mamda"
- swap "md" to yield "madma"
- swap "ma" to yield "madam"
The first line of input gives n, the number of test cases. For each test case, one line of input follows, containing a string of up to 100 lowercase letters. Output consists of one line per test case. This line will contain the number of swaps, or
"Impossible" if it is not possible to transform the input to a palindrome.
【Sample Input】
3 mamad asflkj aabb
【Output for Sample Input】
3 Impossible 2
题意:判断一个串能否通过临近的两个字符多次交换变成回文串,不能输出“Impossible”,能的话输出最少的交换次数。
思路:预处理每个字母出现的次数,若有>=2个字母出现的次数是奇数则不可能。然后从两边向中间贪心,每次先固定前端,然后从后端向中间逐步找,直到找到第一个与前端相同字母时break,将找到的字母向后移,加上移动的次数(不知道为什么可以这么做,网上说这样做 和 每次找最优 最后结果是一样的,暂时还没有证明出来)。若碰到个数为奇数的字母时,将它往后顺移,最后它就会在中央位置了。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #pragma comment (linker,"/STACK:102400000,102400000") #define maxn 8005 #define MAXN 2005 #define mod 1000000009 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-6 #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define FRE(i,a,b) for(i = a; i <= b; i++) #define FREE(i,a,b) for(i = a; i >= b; i--) #define FRL(i,a,b) for(i = a; i < b; i++) #define FRLL(i,a,b) for(i = a; i > b; i--) #define mem(t, v) memset ((t) , v, sizeof(t)) #define sf(n) scanf("%d", &n) #define sff(a,b) scanf("%d %d", &a, &b) #define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c) #define pf printf #define DBG pf("Hi\n") typedef long long ll; using namespace std; char str[maxn]; int num[28]; bool vis[maxn]; int main() { int n,i,j; sf(n); while (n--) { mem(num,0); scanf("%s",str); int len=strlen(str); FRL(i,0,len) num[str[i]-'a']++; int ans=0; FRL(i,0,26) if (num[i]%2) ans++; if (ans>1) { pf("Impossible\n"); continue; } ans=0; int L=0,R=len-1; while (L<len/2) { int j=R; while (j>L) { if (str[L]==str[j]) break; j--; } if (j==L) //找到了应该放在中间的字母,将它往后顺移 { char ch=str[L]; str[L]=str[L+1]; str[L+1]=ch; ans++; } else { ans+=(R-j); FRL(i,j,R) str[i]=str[i+1]; R--; L++; } } pf("%d\n",ans); } return 0; }