题意
一个置换能否为某个置换平方的结果。
思路
置换幂 : https://wenku.baidu.com/view/0bff6b1c6bd97f192279e9fb.html
幂后循环节的长度与原置换长度和幂次之间的gcd有关
当前幂次 = 2
对整个置换的每个循环节长度n
n为奇数, 平方后不变且仍为奇数
n为偶数, 平方后全部分裂成均等的两份,长度可能是奇数,可能是偶数
所以平方后的置换, 循环节长度为偶数的部分一定是由原本2倍长的循环节分裂出来的
统计平方后长度为偶数的循环节成对(长度相同)
代码
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int INF = 0x7f7f7f7f;
const int maxn = 30;
char cipher[ maxn ];
bool vis[ maxn ];
bool getGroup () {
int ans[ maxn ];
memset ( ans, 0, sizeof ( ans ) );
memset ( vis, false, sizeof ( vis ) );
for ( int i = 0; i < 26; ++i ) {
if ( !vis[ i ] ) {
int cnt = 0, k = i;//统计循环节长度
do {
vis[ k ] = true;
k = cipher[ k ];
++cnt;
} while ( k != i );
if ( cnt % 2 == 0 )
ans[ cnt ]++;
}
}
//配对成功,每个偶数长度一定有偶数个
for ( int i = 0; i <= 26; ++i )
if ( ans[ i ] % 2 != 0 )
return false;
return true;
}
int main () {
#ifdef LOCAL
freopen ( "in", "r", stdin );
// freopen("out","w",stdout);
#endif
int t;
scanf ( "%d", &t );
while ( t-- ) {
scanf ( "%s", cipher );
for ( int i = 0; i < 26; ++i )
cipher[ i ] = cipher[ i ] - 'A';
int even = getGroup ();
if ( even )
printf ( "Yes\n" );
else
printf ( "No\n" );
// printf ( "%d\n", even );
}
return 0;
}