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;
}
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;
}
相关文章推荐
- JS 代码调试经验总结(菜鸟必读)
- 爬爬爬之路:OC语言(三) 继承
- xclip----建立终端和剪切板之间的通道
- ASP.NET中服务器控件的生命周期
- JS的bug调试与 常见bug
- 通过代码自定义cell(cell的高度不一致)的步骤
- 记录-Head first java-第五章
- 习题1-4 正弦和余弦 解题报告
- LeetCode 129: Sum Root to Leaf Numbers
- 工作小结
- 4.4.4 Frame Statistics
- C++ 私有构造函数的作用
- 第一章 问题
- OnExit事件 OnChange事件
- 动态规划
- SpringMVC-初识SpringMVC
- Sting 串实现
- 79 Word Search
- Hadoop2.x下安装HBase
- 私有构造函数