第几是谁?
时间限制:
3000 ms | 内存限制:
65535 KB
难度:
3
-
描述
-
现在有"abcdefghijkl”12个字符,将其按字典序排列,如果给出任意一种排列,我们能说出这个排列在所有的排列中是第几小的。但是现在我们给出它是第几小,需要你求出它所代表的序列.
-
输入
-
第一行有一个整数n(0<n<=10000);
随后有n行,每行是一个整数m,它代表着序列的第几小;
输出
- 输出一个序列,占一行,代表着第m小的序列。 样例输入
-
3 1 302715242 260726926
样例输出
-
abcdefghijkl hgebkflacdji gfkedhjblcia
-
-
解题思路:康托展开公式的逆运算
-
举例:
{1,2,3,4,5}的全排列已经从小到大排序,要找出第16个数:
1. 首先用16-1得到15
2. 用15去除4! 得到0余15
3. 用15去除3! 得到2余3
4. 用3去除2! 得到1余1
5. 用1去除1! 得到1余0
有0个数比它小的数是1
所以第一位是1
有2个数比它小的数是3,但1已经在之前出现过了所以是4
有1个数比它小的数是2,但1已经在之前出现过了所以是3
有1个数比它小的数是2,但1,3,4都出现过了所以是5
最后一个数只能是2
所以这个数是14352
参考:康托展开公式
#include<stdio.h> #define N 12 int table[12] = {1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800}; int print[12]; void cantorOpp(int n) { n--; int i,j,record,flag[13] = {0}; for(i=0;i<N;i++) { record = n / table[N-i-1];//i之前有几个数 for(j=1;j<=N;j++) { if(!flag[j])//j从1开始没有出现过的record-1,直到i之前的数全部减完跳出时,此时的j即为本位置的数 { if(record-- == 0) break; } } flag[j] = 1;//标记此数已用过 print[i] = j;//在该位置放入j n %= table[N-i-1] ; } } int main() { int i,n,m; scanf("%d",&n); while(n--) { scanf("%d",&m); cantorOpp(m); for(i=0;i<N;i++) printf("%c",print[i]+96); printf("\n"); } return 0 ; }
-
第一行有一个整数n(0<n<=10000);