题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1027
题解:
第一个数代表着1到n的从小到大的数列,如果n=10,就代表{1,2,3,4,5,6,7,8,9,10}这样的数组,第二个数代表第k小的排列,最后输出就行了。比如{1,2,3,4} 第1小的数列是{1,2,3,4},第二小的数列是{1,2,4,3},方法有两个:
1. 使用next_permutation()函数:
使用时第一个参数代表首地址,第二个参数代表尾地址,比如next_permutation(a,a+n).求第M小的数列,只要让原来从小到大的数列执行m-1次next_permutation()函数即可,这题使用这个方法完全可以AC,只要93ms,但是数据范围如果很大就会超时。就像蔡老师说的“程序员是很懒的”,在使用函数能解决的情况下,就使用这个函数A题。
2.使用阶乘的思想
比如1到100 改变24次(4的阶乘) ,只会对后(4+1)位数字发生变化,前面95个数字依旧不会改变,具体思路见下图:
纯手打,有疑问联系我
AC代码1:(用阶乘讨论)
#include<stdio.h>
#include<string.h>
int a[10]={1,1,2,6,24,120,720,5040};
int b[10];
int main ()
{
int n,m,i,k,t;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n-8;i++)
printf("%d ",i);
for(k=0;i<=n;i++)
b[k++]=i;
for(i=n>8?8:n;i>1;i--)
{
t=(m-1)/a[i-1];
for(k=0;k<8&&k<n;k++)
{
if(b[k]&&t==0)
{
printf("%d ",b[k]);
b[k]=0;
break;
}
else if(b[k])
t--;
}
m=(m-1)%a[i-1]+1;
}
for(k=0;k<8&&k<n;k++)
if(b[k])
printf("%d\n",b[k]);
}
return 0;
}
AC代码2:(用函数解决)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define N 1047
int num[N];
int main()
{
int n , m , i ,k;
while(~scanf("%d%d",&n,&m))
{
memset(num,0,sizeof(num));
for(i = 0 ; i < n ; i++)
{
num[i] = i+1;
}
for(i = 1 ; i < m ; i++)
{
next_permutation(num,num+n);
}
for(i = 0 ; i < n-1 ; i++)
printf("%d ",num[i]);
printf("%d\n",num[n-1]);
}
return 0;
}