Description
Any case of shuffling of n cards can be described with a permutation of 1 to n. Thus there are totally n! cases of shuffling. Now suppose there are 5 cards, and a case of shuffle is <5, 3, 2, 1, 4>, then the shuffle will be:
Before shuffling:1, 2, 3, 4, 5
The 1st shuffle:5, 3, 2, 1, 4
The 2nd shuffle:4, 2, 3, 5, 1
The 3rd shuffle:1, 3, 2, 4, 5
The 4th shuffle:5, 2, 3, 1, 4
The 5th shuffle:4, 3, 2, 5, 1
The 6th shuffle:1, 2, 3, 4, 5(the same as it is in the beginning)
You’ll find that after six shuffles, the cards’ order returns the beginning. In fact, there is always a number m for any case of shuffling that the cards’ order returns the beginning after m shuffles. Now your task is to find the shuffle with the largest m. If there is not only one, sort out the one with the smallest order.
Input
The first line of the input is an integer T which indicates the number of test cases. Each test case occupies a line, contains an integer n (1 ≤ n ≤ 100).
Output
Each test case takes a line, with an integer m in the head, following the case of shuffling.
Sample Input
2
1
5
Sample Output
1 1
6 2 1 4 5 3
题意
求解让一个置换变为单位置换的最大步数,并把置换按字典序输出,也就是Tk = e,有多个T,但是T的循环节长度之和为n,求解k的最大值,并且T是字典序最小的那一个。
思路
把n分解成若干个数,使得他们的lcm最大。很明显在所取的数都是素数幂的时候是最大的情况,并且最好每个循环节的长度不同,所以可以用递归来枚举所有的分解情况,而且由于要输出序最小的,所以对于剩下的数可以直接单独都作为一个循环,这样就可以使得序最小了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<ctype.h>
#include<vector>
#include<algorithm>
#include<sstream>
#define PI acos(-1.0)
using namespace std;
typedef long long ll;
typedef unsigned long long llu;
const int inf = 0x3f3f3f3f;
const ll lnf = 0x3f3f3f3f3f3f3f3f;
const int maxn = 210;
bool ha[maxn];
int p[maxn],lp;
void prim() //筛素数,n比较小,就应最简单的筛法了
{
memset(ha,true,sizeof(ha));
lp=0;
for(int i=2;i<maxn;i++){
if(ha[i]){
p[lp++]=i;
for(int j=i*i;j<maxn;j+=i)
ha[j]=false;
}
}
}
int st[maxn],maxm,c[maxn],lc;
void dfs(int remain,int k)
{
if(remain<p[k]){
int m = 1;
for(int i=0;i<k;i++) //求lcm
if(st[i])
m *= st[i];
if(m>maxm){
maxm = m; //更新最大k值
lc = 0; //更新循环
for(int i=0;i<k;i++)
if(st[i])
c[lc++] = st[i];
while(remain--) //剩余的补1
c[lc++] = 1;
}
}
else{
st[k] = 0;
dfs(remain,k+1);
for(st[k]=p[k];st[k]<=remain;st[k]*=p[k])
dfs(remain-st[k],k+1);
}
}
int main(void)
{
int t,n;
prim();
scanf("%d",&t);
while(t--){
scanf("%d",&n);
if(n==1){ //特判
printf("1 1\n");
continue;
}
//找寻最大lcm,
maxm=1;lc=0; //最大k值,循环节个数
dfs(n,0);
sort(c,c+lc); //按循环节长度,由小到大排
printf("%d",maxm);
int k=1,tmp;
for(int i=0;i<lc;i++){
tmp = k++;
for(int j=1;j<c[i];j++)
printf(" %d",k++);
printf(" %d",tmp);
}
printf("\n");
}
return 0;
}