首页 > 代码库 > poj 3128 Leonardo's Notebook (置换群的整幂运算)

poj 3128 Leonardo's Notebook (置换群的整幂运算)

题意:给你一个置换P,问是否存在一个置换M,使M^2=P

思路:资料参考 《置换群快速幂运算研究与探讨》 https://wenku.baidu.com/view/0bff6b1c6bd97f192279e9fb.html

结论一: 一个长度为 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… 的元素的连接

 

考虑某个置换的平方。对于其中长度为奇数的轮换,平方以后这个轮换仍然为一个轮换只是元素顺序换了。一个长度为偶数的轮换,平方以后就变为两个大小相等的轮换了。因此,对于给定的置换,当中所有长度为奇数的轮换,可以直接当做是它原先平方产生的。而长度为偶数的轮换,必须一一配对,当做原先拆出来的。满足这个条件,就是平方。

 

代码:

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

int main(int argc, char const *argv[])
{
    int t;
    int num[26];
    bool visit[26];
    string str;
    cin>>t;
    while(t--)
    {
       cin>>str;
       for(int i=0;i<str.length();i++)
       {
          num[i]=str[i]-A;
       }
       int cnt[27];
       memset(visit,false,sizeof(visit));
       memset(cnt,0,sizeof(cnt));
       for(int i=0;i<26;i++)
       {
           if(!visit[i])
           {
              visit[i]=true;
              int tmp=num[i];
              int len = 1;
              while(tmp!=i)
              {
                 visit[tmp]=true;
                 tmp=num[tmp];
                 len++;
              }
              cnt[len]++;
           }
       }
       int flag=1;
       for(int i=2;i<=26;i+=2)
       {
           if(cnt[i]%2)
           {
               flag=0;
               break;
           }
       }
       if(flag) cout<<"Yes"<<endl;
       else cout<<"No"<<endl;
    }
    return 0;
}

 

poj 3128 Leonardo's Notebook (置换群的整幂运算)