poj 3128 关于置换群的规律

Leonardo's Notebook
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 2433   Accepted: 1037

Description

— I just bought Leonardo's secret notebook! Rare object collector Stan Ucker was really agitated but his friend, special investigator Sarah Kepticwas unimpressed. 
— How do you know it is genuine? 
— Oh, it must be, at that price. And it is written in the da Vinci code. Sarah browsed a few of the pages. It was obvious to her that the code was a substitution cipher, where each letter of the alphabet had been substituted by another letter. 
— Leonardo would have written the plain-text and left it to his assistant to encrypt, she said. And he must have supplied the substitution alphabet to be used. If we are lucky, we can find it on the back cover! She turned up the last page and, lo and behold, there was a single line of all 26 letters of the alphabet: 
QWERTYUIOPASDFGHJKLZXCVBNM 
— This may be Leonardo's instructions meaning that each A in the plain-text was to be replaced by Q, each B withW, etcetera. Let us see... To their disappointment, they soon saw that this could not be the substitution that was used in the book. Suddenly, Stan brightened. 
— Maybe Leonardo really wrote the substitution alphabet on the last page, and by mistake his assistant coded that line as he had coded the rest of the book. So the line we have here is the result of applying some permutation TWICE to the ordinary alphabet! Sarah took out her laptop computer and coded fiercely for a few minutes. Then she turned to Stan with a sympathetic expression. 
— No, that couldn't be it. I am afraid that you have been duped again, my friend. In all probability, the book is a fake. 

Write a program that takes a permutation of the English alphabet as input and decides if it may be the result of performing some permutation twice. 

Input

The input begins with a positive number on a line of its own telling the number of test cases (at most 500). Then for each test case there is one line containing a permutation of the 26 capital letters of the English alphabet.

Output

For each test case, output one line containing Yes if the given permutation can result from applying some permutation twice on the original alphabet string ABC...XYZ, otherwise output No.

Sample Input

2
QWERTYUIOPASDFGHJKLZXCVBNM
ABCDEFGHIJKLMNOPQRSTUVWXYZ

Sample Output

No
Yes

初看这道题真的一脸懵,就去搜。
原来有规律qwq。代码的实现很简单,关键是涉及这方面的知识。

摘自:https://blog.csdn.net/lianai911/article/details/49474067

题目大意:

给你一行共 26 个字母,代表一个置换。问:这个置换能否为某个置换平方的结果。

 

解题思路:

这道题可参考《置换群快速幂运算研究与探讨》,里边有详解。这里放上结论。

结论一: 一个长度为 l 的循环 T,l 是 k 的倍数,则 T^k 是 k 个循环的乘积,每个

循环分别是循环 T 中下标 i mod k=0,1,2… 的元素按顺序的连接。 
结论二:一个长度为 l 的循环 T,gcd(l,k)=1,则 T^k 是一个循环,与循环 T 不一

定相同。

结论三:一个长度为 l 的循环 T,T^k 是 gcd(l,k)个循环的乘积,每个循环分别是循

环 T 中下标 i mod gcd(l,k)=0,1,2… 的元素的连接。 

这倒题中,应用上边的结论来判断这个置换是否为某个置换平方的结果。

一个置换平方可得到:循环节为奇数的置换的平方仍为奇数项的置换,循环节为偶数

的置换的平方分裂成了两个循环节相同的置换。

那么当前置换是由什么置换而来的:

对于奇数项的置换,有可能是由奇数项的置换平方得到的,也有可能是有偶数项的置

换平方得到的。对于偶数项的置换,它一定是原始置换为偶数项的置换分裂得到的。

而且当前置换中偶数项的置换一定成对出现。

那么问题就变为了:对于偶数项的置换,是否成对出现。

那么,我们现在查找 26 个字母的所有置换,计算出每个置换的循环节长度。统计循

环节长度的个数。遍历查找偶数项的置换数目,如果出现奇数,则输出"No",否则

输出"Yes"。


 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 const int maxn=30;
 6 char a[maxn];
 7 int b[maxn];
 8 int c[maxn];
 9 bool flag[maxn];
10 
11 bool solve()
12 {
13     memset( flag, 0, sizeof flag);
14     memset( c, 0, sizeof c);
15     bool cheek=true;
16     for(int i=0;i<26;i++){
17         if(!flag[i]){
18             flag[i]=1;
19             int num=1,next;
20             next=b[i];
21             while( !flag[next]){
22                 flag[next]=1;
23                 num++;
24                 next=b[next];
25             }
26             c[num]++;
27         }
28     }
29     for(int i=2;i<=26;i+=2){
30         if(c[i]&1){
31             cheek=false;
32             break;
33         }
34     }
35     return cheek;
36 }
37 
38 int main()
39 {
40     int n;
41     while( ~scanf("%d",&n)){
42         getchar();
43         while(n--){
44             scanf("%s",a);
45             for(int i=0;i<26;i++)
46                 b[i]=a[i]-'A';
47             bool cheek=solve();
48             if(cheek) printf("Yes\n");
49             else printf("No\n");
50         }
51 
52     }
53 
54     return 0;
55 }

 

posted @ 2018-05-17 23:49  flyer_duck  阅读(366)  评论(0编辑  收藏  举报