题意:给定两个整数N、M。将1~N排列组合,按字典序从小到大排列,求出排在第M个的排列。
虽然N的范围很大,到1000,1000的阶乘很吓人呀,但是M的范围只到10000,而8的阶乘就已经超过10000了,所以无论N多大,我们最多只要考虑后八位的排列组合问题。
先判断M与阶乘数的大小,确定要考虑后几位的排列组合。假设是考虑后x位的排列组合,先将1~N-x-1顺序输出。然后处理剩余的数:用M对(x-1)的阶乘求商a,取余赋值给M自身。若M为0,则倒数第x位取第a大的数,剩余几位倒序排列;若M不为0,则倒数第x位取第(a+1)大的数,再用同样方法考虑后(x-1)位数,以此类推。
#include
#include
#include
using namespace std;
int biao[9]= {1,1,2,6,24,120,720,5040,40320};
int main()
{
int n,m,x,a,cnt;
int rest[2],store[9];
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i = 0; i < 9; i++)
store[i] = 1005;
for(int i = 1; i <= 8; i++)
if(biao[i] > m)
{
x = i;
break;
}
for(int i = 1; i <= n - x; i++)
printf("%d ",i);
for(int i = 1; i <= x; i++)
store[i] = n - x + i;
for(int i = x - 1; i >= 1; i--)
{
sort(store, store + 9);
a = m / biao[i];
m %= biao[i];
if(m)
{
printf("%d ",store[a]);
store[a] = 1005;
}
else
{
printf("%d ",store[a - 1]);
store[a - 1] = 1005;
break;
}
}
sort(store, store + 9);
for(int i = 8; i > 0; i--)
if(store[i] != 1005)
printf("%d ",store[i]);
printf("%d\n",store[0]);
}
}