由置换群的性质可以知道
T^k=e(T为置换,e为单位置换)的k等于所有轮换长度的最小公倍数
因此对于一个确定元素个数的置换,最优的解应当是尽可能地将其分解为一组和为n,最小公倍数最大的数
而又因为要求字典序最小,因此对于任何对最小公倍数没有贡献的数都没有必要
全部用1来替代就好了。
因此会想到搜质数就好了,代码如下
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int SIZEN=55;
int prime[SIZEN],cnt;
int ans[SIZEN],t_ans[SIZEN];
int cnt2,ans_cnt;
int Max,n;
bool isprime(int x){
if(x==2) return 1;
for(int i=2;i*i<=x;i++)
if(x%i==0) return 0;
return 1;
}
int pow(int a,int b){
int ret=1,x=a;
while(b){
if(b&1) ret*=x;
x=x*x;
b>>=1;
}
return ret;
}
void dfs(int u,int mul,int add){
if(mul>Max){
ans_cnt=cnt2;
memcpy(ans,t_ans,sizeof(t_ans));
Max=mul;
}
for(int i=u;i<cnt;i++){
if(add+prime[i]>n) break;
for(int j=1;;j++){
int tt=pow(prime[i],j);
if(tt+add>n) break;
t_ans[cnt2++]=tt;
dfs(i+1,mul*tt,add+tt);
cnt2--;
}
}
}
void init(){
cnt=0;
for(int i=2;i<=50;i++)
if(isprime(i)) prime[cnt++]=i;
//printf("prime: ");
//for(int i=0;i<cnt;i++) printf("%d ",prime[i]);printf("\n");
}
void solve(){
scanf("%d",&n);
cnt2=Max=0;
dfs(0,1,0);
int tmp=0;
for(int i=0;i<ans_cnt;i++) tmp+=ans[i];
for(int i=0;i<n-tmp;i++) ans[ans_cnt++]=1;
sort(ans,ans+ans_cnt);
int j=1,ttcnt=0;
printf("%d",Max);
for(int i=0;i<ans_cnt;i++){
int tj=j;ttcnt+=ans[i];
for(j++;j<=ttcnt;j++) printf(" %d",j);
printf(" %d",tj);
}
printf("\n");
}
int main()
{
int _;
init();
scanf("%d",&_);
while(_--) solve();
return 0;
}