您的位置:首页 > 其它

POJ3128 Leonardo's Notebook【置换群】

2015-10-28 21:25 155 查看
题目链接:

http://poj.org/problem?id=3128

题目大意:

给你一行共 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"。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;

char s[33];
bool vis[33];
int ss[33],Cnt[33];

int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(s,0,sizeof(s));
memset(vis,false,sizeof(vis));
memset(Cnt,0,sizeof(Cnt));
scanf("%s",s);
for(int i = 0; i < 26; ++i)
ss[i] = s[i] - 'A';
int flag = 1;
for(int i = 0; i < 26; ++i)
{
if(vis[i] == 0)
{
vis[i] = 1;
int temp = ss[i];
int num = 1;
while(temp != i)
{
vis[temp] = 1;
temp = ss[temp];
num++;
}
Cnt[num]++;
}
}

for(int i = 2; i < 26; i+=2)
if(Cnt[i]%2)
{
flag = 0;
break;
}

if(flag)
printf("Yes\n");
else
printf("No\n");

}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: