题目:POJ3128.
题目大意:给定一个长度为
26
26
26的置换,问这个置换有没有平方根.
数据组数
≤
500
\leq 500
≤500.
直接考虑置换的平方根有些困难,所以我们先考虑置换的平方.
由于一个置换可以被拆为一些轮换的乘积,所以我们考虑对于拆出来的每个轮换平方后会发生什么.
细细一思考,轮换 f ( x ) = x    m o d    k + 1 f(x)=x\,\,mod\,\,k+1 f(x)=xmodk+1平方后变成置换 f ( x ) = x + 1    m o d    k + 1 f(x)=x+1\,\,mod\,\,k+1 f(x)=x+1modk+1,此时有两种情况.
一种是长度为奇数,那么从 1 1 1出发遍历置换会经过路线 1 → 3 → 5 → ⋯ → n → 2 → 4 → ⋯ → n − 1 → 1 1\rightarrow 3\rightarrow 5\rightarrow\cdots\rightarrow n\rightarrow 2\rightarrow 4\rightarrow \cdots\rightarrow n-1\rightarrow 1 1→3→5→⋯→n→2→4→⋯→n−1→1,发现它还是一个轮换.
另一种是长度为偶数,此时从 1 1 1出发会经过路线 1 → 3 → 5 → ⋯ → n − 1 → 1 1\rightarrow 3\rightarrow 5\rightarrow\cdots\rightarrow n-1\rightarrow 1 1→3→5→⋯→n−1→1,从 2 2 2出发会经过路线 → 2 → 4 → 6 → ⋯ → n → 2 \rightarrow 2\rightarrow 4\rightarrow 6\rightarrow \cdots\rightarrow n\rightarrow 2 →2→4→6→⋯→n→2,发现它变成了两个轮换.
也就是说,对于长度为奇数的轮换一定有平方根,而对于长度为偶数的轮换必须要与另一个长度相等的轮换在平方根后合并为一个轮换.
那么解法就很简单了,暴力拆出每一个轮换,计算每一种长度的轮换数量,判断有偶数长度的轮换数量为奇数则无平方根,否则就有平凡根.
时间复杂度 O ( n ) O(n) O(n).
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=26;
char s[N+9];
int p[N+9];
int vis[N+9],cnt[N+9],ans;
Abigail into(){
scanf("%s",s+1);
}
Abigail work(){
for (int i=1;i<=N;++i)
p[i]=s[i]-'A'+1,vis[i]=cnt[i]=0;
for (int i=1;i<=N;++i)
if (!vis[i]){
int flag=1;
vis[i]=1;
for (int j=p[i];j^i;j=p[j]) ++flag,vis[j]=1;
cnt[flag]^=1;
}
ans=1;
for (int i=2;i<=N;i+=2)
if (cnt[i]) {ans=0;return;}
}
Abigail outo(){
puts(ans?"Yes":"No");
}
int main(){
int T;
scanf("%d",&T);
while (T--){
into();
work();
outo();
}
return 0;
}