| Time Limit: 1000MS | Memory Limit: 65536K | |
| Total Submissions: 1791 | Accepted: 787 |
Description
— I just bought Leonardo‘s secret notebook! Rare object collector Stan Ucker was really agitated but his friend, special investigator Sarah Kepticwas unimpressed.
Input
Output
Sample Input
2 QWERTYUIOPASDFGHJKLZXCVBNM ABCDEFGHIJKLMNOPQRSTUVWXYZ
Sample Output
No Yes
Source
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次方。
题目大意:给出一个A~Z的置换,问是否可以被表示为一个置换的平方(即G=G‘*G‘)。
通过观察可以发现,一个置换乘上它本身,其中长度为偶数的循环节必然会分裂为两个长度相等的循环节,长度为奇数的循环节还是一个循环节,长度不变。如:
2341*2341=3412 (2341是一个循环节,平方后分裂为两个长度为2的循环节[13][24])
23451*23451=34512 (23451是一个循环节,平方后还是长度为5的循环节)
所以,给出的置换中长度为偶数的循环节必然是原置换中的循环节分裂出来的,而长度为奇数的循环节有可能是原置换中的循环节分裂出来的。因为只要判断能否被表示,所以可以忽略长度为奇数的循环节,只对长度为偶数的循环节进行考虑即可。
因为一个长度为偶数的循环节分裂出来的两个循环节的长度相等且同为原循环节长度的一半。所以,只要给出置换中所包含的长度为偶数的循环节能一一配对,那么就必然可以被表示为另一个置换的平方。
关键:循环节长度为偶数的循环节个数必须为偶数。
代码:
#include <iostream>
#include <string.h>
using namespace std;
const int maxn=28;
int num[maxn];
int vis[maxn];
int loop[maxn];
int main()
{
int t;cin>>t;
string s;
while(t--)
{
memset(vis,0,sizeof(vis));
memset(loop,0,sizeof(loop));
cin>>s;
for(int i=0;i<26;i++)
num[i+1]=s[i]-‘A‘+1;
for(int i=1;i<=26;i++)
{
int count=0,tag;
tag=i;
while(!vis[tag])
{
count++;//每个循环节的长度
vis[tag]=1;
tag=num[tag];
}
loop[count]++;//长度为count的循环节的个数++
}
int flag=0;
for(int i=2;i<=26;i+=2)
if(loop[i]%2==1)//长度为偶数的循环节有奇数个
{
flag=1;
break;
}
if(flag)
cout<<"No"<<endl;
else
cout<<"Yes"<<endl;
}
return 0;
}
[ACM] poj 3128 Leonardo's Notebook (置换群,循环节),布布扣,bubuko.com
[ACM] poj 3128 Leonardo's Notebook (置换群,循环节)
原文:http://blog.csdn.net/sr_19930829/article/details/22718973