/*1027 Ignatius and the Princess II*/ #include<stdio.h> #include<string.h> #include<stdlib.h> int arr[9]; int q[1005]; int n,m; void init() { int i; int res; for(i = 1,res = 1;i <= 7;i++){ res *= i; arr[i] = res; } } int find_min(int k) { int min = n+1; int i; for(i=k+1;i<=n;i++) { if(q[i] < q[min] && q[i] > q[k]) min =i; } return min; } void print() { int i; printf("%d",q[1]); for(i = 2;i <= n;i++) printf(" %d",q[i]); printf("/n"); } int comp(const void *a,const void *b) { return *(int *)a - *(int *)b; } int comp1(const void *a,const void *b) { return *(int *)b - *(int *)a; } int main() { int i,j; int min,sum; int temp; init(); while(scanf("%d %d",&n,&m) == 2){ for(i = 0;i <= n+1;i++) q[i] = i; for(i = 7,sum = 0;i > 0;i--){ sum += arr[i]; if(sum < m){ min = find_min(n-i); q[min] ^= q[n-i]; q[n-i] ^= q[min]; q[min] ^= q[n-i]; qsort(&q[n-i+1],i,sizeof(int),comp); i++; } else if(sum > m) sum -= arr[i]; if(sum == m){ qsort(&q[n-i+1],i,sizeof(int),comp1); print(); break; } } } return 0; } //我激动了,可能在大牛看来是白痴!不过这题是你一点都没百度,没问其它人,自己想出来的方法,而且按时间排排到73! //我己经好久没试过这样的感觉了,因为现在一直就在做新的东西,而且 个人来说就很少能自己想一个 //方法出来解决问题,大半都是站在别人的成果上去做的,总之激动ing~~~~~下面讲下我的方法^-^ //题目m的最大值为10000,不是很大 //想了想,一个n个数的序列的情况就是全排列,也就是n!。 //我把1-n,存入一个数组q[]中,这也是最小的那个。 //首先题意的第几小序列是要让尽量小的数放在前面位置,所以我们应不到必要时不要动前面的数 //也就是应该从后面一点一点地改变序列,如果m为1,则不用动,如果m为2则要反倒数两个数对换 //我们还是假设有序列{1,2,3,4,5,6} //m==1:{1,2,3,4,5,6} //m==2:{1,2,3,4,6,5} //m==3:{1,2,3,5,6,4},当m为3时,只是变换倒数的两个数已不行了,那么十么时候才算不能呢? //就是当我们现在要移动倒数的i个数时的全排列,也就是i!<m时,我们就不得不动变动第i-1个数。 //嗯,现在问题己有点明朗了。 //现在我们再从最坏的情况考虑,也就是我们可能要变动全部n个数,这时m==n!(注意题目m最大是10000<8!) //如果n!>m,也就是说我们不必变动全部n个数,我们又考虑我们有可能要变动倒数的n-1个数,也就是第(n-1)!个序列正好为第m个 //但这里m有两种情况可能 //a).(n-1)!==m,这时所要找的序列就是倒数的n-1个数(前面的数不用管)最大(相对于题目意义中的最小)序列,也就是这n-1个 //数我们要尽可能的大的数放在前,这是我们把这n-1个数从大到小排列,再和前面的数一起输出就行了。 //b).(n-1)!< m <n!,这时倒数第n个数也得变动,这样m,由于我们要尽可能把上的数放在前,所以们从倒数的n-1个数中找到最小的那个与 //倒数第n个数对换,然后再把现在倒数的n-1个数从小到大排序。这样序列的第1个数就确定了,现在未确定的就倒数的n-1个数, //这里我们应用一个变量sum==(n-1)!记下当前序列为第几个序列,然后我们考虑倒数的(n-2)个数,一直这样重复直到当sum == m时把a)中的1换成i //实际上是一个一个数的确定,就是一个第归过程。