poj 3128 Leonardo's Notebook (置换群)

题意:

一个长度为26的字符串,包含26个字母,问这个置换能否是其他某个置换的平方。

题解:

首先引入定理:

1.任意一个长为 L 的置换的k次幂,会把自己分裂成gcd(L,k) 分, 并且每一份的长度都为 L / gcd(l,k)
2.假如 d = gcd(L,K),l = L / gcd(L,k),那么我们只需要找到d个长为l的循环,将他们交错循环连接成一个长为 d * l 的大循环, 这样一个过程就相当于开k次方。

如果一个置换平方后,长度为奇数的循环节任然是奇数,长度为偶数的循环节会分解成两个长度为偶数的循环节,那么这个置换要是另外一个置换的平方,这个置换中偶数循环节要能一一配对,那么偶数循环节的个数肯定是偶数个。

解决这个问题:偶数循环节的个数是否是偶数个。

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define B(x) (1<<(x))
using namespace std;
typedef long long ll;
void cmax(int& a,int b){ if(b>a)a=b; }
void cmin(int& a,int b){ if(b<a)a=b; }
void cmax(ll& a,ll b){ if(b>a)a=b; }
void cmin(ll& a,ll b){ if(b<a)a=b; }
void add(int& a,int b,int mod){ a=(a+b)%mod; }
void add(ll& a,ll b,ll mod){ a=(a+b)%mod; }
const int oo=0x3f3f3f3f;
const int MOD=2012;
const int maxn=30;
char str[maxn];
int a[maxn],vis[maxn];
int cnt[maxn],num;

int main(){
    //freopen("E:\\read.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%s",str+1);
        for(int i=1;i<=26;i++)a[i]=str[i]-'A'+1;
        memset(vis,0,sizeof vis);
        memset(cnt,0,sizeof cnt);
        for(int i=1;i<=26;i++){
            if(!vis[i]){
                vis[i]=1;
                num=1;
                int temp=a[i];
                while(!vis[temp]){
                    num++;
                    vis[temp]=1;
                    temp=a[temp];
                }
                cnt[num]++;
            }
        }
        int f=1;
        for(int i=2;i<=26;i+=2){
            if(cnt[i]%2!=0){
                f=0;
                break;
            }
        }
        if(f) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}





你可能感兴趣的:(poj 3128 Leonardo's Notebook (置换群))