UVA12103 —— Leonardo's Notebook —— 置换分解
题目链接:https://vjudge.net/problem/UVA-12103
题意:
给出大写字母“ABCD……Z”的一个置换B,问是否存在一个置换A,使得A^2 = B。
题解:
对于置换,有以下结论:
其中“结论三”是一般性结论。
因此:
1.对于长度为len的循环T,则T^2为gcd(len,2)个循环。即:当len为偶数时,T^2分解成gcd(len,2)=2个循环,且每个循环的长度为len/2;当len为奇数时,T为gcd(len,2)=1个循环。
2.根据第一点的分析,将置换B分解成若干个循环,并统计每种长度下循环的个数。
3.在A^2里面:对于长度len为奇数的循环,它可以是在A-->A^2的过程中由一个长度len为奇数的循环演变过来的,也有可能是在A-->A^2的过程中由一个长度为2*len的循环分裂过来。对于长度len为偶数的循环,它必定是在在A-->A^2的过程中由一个长度为2*len的循环分裂过来。
4.根据第3点,可知:对于A^2的循环,奇数长度的循环没有要求,但偶数长度的循环必定是成双成对的,因此才能由一个偶数长度的循环分裂成两个等成的循环。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 2e9; 15 const LL LNF = 9e18; 16 const int MOD = 1e9+7; 17 const int MAXN = 30; 18 19 char str[MAXN]; 20 int cnt[MAXN], vis[MAXN]; 21 22 int main() 23 { 24 int T; 25 scanf("%d", &T); 26 while(T--) 27 { 28 scanf("%s", str); 29 memset(cnt, 0, sizeof(cnt)); 30 memset(vis, 0, sizeof(vis)); 31 for(int i = 0; i<26; i++) 32 if(!vis[i]) 33 { 34 int j = i, n = 0; 35 do 36 { 37 vis[j] = 1; 38 j = str[j]-'A'; 39 n++; 40 }while(j!=i); 41 cnt[n]++; 42 } 43 44 bool flag = true; 45 for(int i = 2; i<=26; i += 2) 46 if(cnt[i]%2) 47 flag = false; 48 printf("%s\n", flag?"Yes":"No"); 49 } 50 }