题意
给出26个大写字母的置换 $B$,问是否存在一个置换 $A$,使得 $A^2=B$.
分析
首先,若A=BC,若B和C都能表示成两个相同循环的乘积,则A也能。
因为,不相交的循环的乘积满足交换律和结合律,
设 $B=(b_1\ b_2 \ b_3)^2, C=(c_1 \ c_2 \ c_3 \ c_4)^2$,则 $A^2 = (b_1\ b_2 \ b_3)^2 \times (c_1 \ c_2 \ c_3 \ c_4)^2 = ((b_1\ b_2 \ b_3) \times (c_1 \ c_2 \ c_3 \ c_4))^2$.
其次,考察两个相同循环的乘积,
$$(a_1 \ a_2 \ a_3)(a_1 \ a_2 \ a_3) = (a_1 \ a_3 \ a_2)\\
(b_1 \ b_2\ b_3\ b_4)(b_1 \ b_2\ b_3\ b_4) = (b_1 \ b_3)(b_2 \ b_4)$$
不难总结出规律:当 $n$ 为奇数时结果也是一个长度为 $n$ 的循环;当 $n$ 为偶数时分裂成两个长度为 $n/2$ 的循环。
反过来,偶数长的循环需要两两配对,奇数长的不用管。
#include//stdc++.h> using namespace std; char B[30]; int vis[30], cnt[30]; int main() { int T; scanf("%d", &T); while(T--) { scanf("%s", B); memset(vis, 0, sizeof(vis)); memset(cnt, 0, sizeof(cnt)); for(int i = 0;i < 26;i++) { if(!vis[i]) //找到一个从i开始的循环 { int j = i, tmp = 0; do { vis[j] = 1; j = B[j] - 'A'; tmp++; }while(i != j); cnt[tmp]++; } } bool flag = true; for(int i = 2;i <= 26;i += 2) //只管偶数长度的即可 if(cnt[i] % 2) flag = false; if(flag) printf("Yes\n"); else printf("No\n"); } return 0; }