Leonardo的笔记本LA 3641——置换的乘法

时间:2019-09-03
本文章向大家介绍Leonardo的笔记本LA 3641——置换的乘法,主要包括Leonardo的笔记本LA 3641——置换的乘法使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题意

给出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<bits//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;
}

原文地址:https://www.cnblogs.com/lfri/p/11456267.html