Description
一个关于n个元素的排列是指一个从{1, 2, …, n}到{1, 2, …, n}的一一映射的函数。这个排列p的秩是指最小的k,使得对于所有的i = 1, 2, …, n,都有p(p(…p(i)…)) = i(其中,p一共出现了k次)。
例如,对于一个三个元素的排列p(1) = 3, p(2) = 2, p(3) = 1,它的秩是2,因为p(p(1)) = 1, p(p(2)) = 2, p(p(3)) = 3。
给定一个n,我们希望从n!个排列中,找出一个拥有最大秩的排列。例如,对于n=5,它能达到最大秩为6,这个排列是p(1) = 4, p(2) = 5, p(3) = 2, p(4) = 1, p(5) = 3。
当我们有多个排列能得到这个最大的秩的时候,我们希望你求出字典序最小的那个排列。对于n个元素的排列,排列p的字典序比排列r小的意思是:存在一个整数i,使得对于所有j < i,都有p(j) = r(j),同时p(i) < r(i)。对于5来说,秩最大而且字典序最小的排列为:p(1) = 2, p(2) = 1, p(3) = 4, p(4) = 5, p(5) = 3。
Input
输入的第一行是一个整数T(T <= 10),代表数据的个数。
每个数据只有一行,为一个整数N。
Output
对于每个N,输出秩最大且字典序最小的那个排列。即输出p(1), p(2),…,p(n)的值,用空格分隔。
Sample Input
2
5
14
Sample Output
2 1 4 5 3
2 3 1 5 6 7 4 9 10 11 12 13 14 8
Data Constraint
对于40%的数据,有1≤N≤100。
对于所有的数据,有1≤N≤10000。
思路
显然,我们肯定是把它拆成形如p1x1,p2x2,p3x3……大小的环(p是质数)
原因:可以发现,这些数最总经过若干次后便会自己其实就是一直在走环(可能走多次),一周期就是还的大小,那么多个周期的共同周期就是它们的lcm,所以我们应该让所有数互质。
我们可以用DP解决这个问题:f[i][j]为前i个质数,和为j的最大乘积。转移十分暴力,枚举质数即可(注意如果指数为0,那么就没必要占用一个位置)
我们要知道你那个乘积是怎么来的。我们只要用g数组记录一下所用质数和前驱即可
代码
#include<bits/stdc++.h>
using namespace std;
#define N 10077
#define M 1377
bool bz[N];
double f[M][N];
int p[M],a[N],ans[N],Q[20],g[M][N];
int T,n;
void pre()
{
for(int i=2; i<=n; i++)
{
if(!bz[i])
{
bz[i]=1;
p[++p[0]]=i;
}
for(int j=1; j<=p[0]; j++)
{
if(i*p[j]>n) break;
bz[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
}
void dp()
{
for(int i=0; i<p[0]; i++)
{
for(int j=0; j<=n; j++)
{
if(f[i][j]>f[i+1][j])
{
f[i+1][j]=f[i][j];
g[i+1][j]=j;
}
int k=p[i+1];
double del=log(p[i+1]),t=del;
for(; k+j<=n; k*=p[i+1],t+=del)
{
if(f[i][j]+t>=f[i+1][j+k])
{
f[i+1][j+k]=f[i][j]+t;
g[i+1][j+k]=j;
}
}
}
}
}
void solve()
{
double mx=0;
int now=n;
a[0]=0;
for(int i=1; i<=n; i++)
if(f[p[0]][i]>mx)
{
mx=f[p[0]][i];
now=i;
}
for(int i=1; i<=n-now; i++) a[++a[0]]=1;
int i=p[0];
while(i)
{
a[++a[0]]=now-g[i][now];
now=g[i][now];
i--;
}
}
void find()
{
sort(a+1,a+a[0]+1);
int w=0,k=1;
while(!a[k]&&k<=p[0]) k++;
for(int i=1; i<=n; i++)
{
if(i==w+a[k])
{
ans[i]=w+1;
w+=a[k];
k++;
}else ans[i]=i+1;
}
}
void print()
{
for(int i=1; i<n; i++) printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}
int main()
{
scanf("%d",&T);
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
for(int i=1; i<=T; i++)
{
scanf("%d",&Q[i]);
n=max(n,Q[i]);
}
pre();
dp();
for(int i=1; i<=T; i++)
{
n=Q[i];
solve();
find();
print();
}
return 0;
}