1 /**
2 大意: 给定16进制数的16个字母,,求第k大的数,,要求数的长度最大为8.,并且每个数互不相同。
3 思路: 从高到低挨个枚举,每一位能组成的排列数 ,拿最高位来说,能做成的排列数为15*A(15,len-i)
4 第二位 A(14,len-2)。。这样就可以找到k大的数的长度
5 接下来 。找第k大的数。同上理 ,挨个枚举每一位即可。。若加上该位的排列数大于k,则该位就是这个数,继续枚举下一位
6 **/
7
8 /** 大神思路
9 首先确定数字串的长度Len:从大到小枚举Len,每个Len下有15*P(15, Len-1)个数字串。每次用这个个数扣除输入的序数Count,直到序数Count将扣为负数时停止,就确定了长度Len。
10
11 然后从高位到低位,从大到小确定每位数字:设当前确定的数字为第i位,则第i位的任何一个取值,都有P(16 - (Len - i + 1), i - 1)个数字串将已确定的第1到i位作为前缀。每次用这个个数扣除输入的序数Count,直到序数Count将扣为负数时停止,就确定了当前位的数字。
12
13 注意不能有前导0。
14 **/
15 #include <iostream>
16
17 using namespace std;
18 char num[16]={‘0‘,‘1‘,‘2‘,‘3‘,‘4‘,‘5‘,‘6‘,‘7‘,‘8‘,‘9‘,‘A‘,‘B‘,‘C‘,‘D‘,‘E‘,‘F‘};
19 int ans[10];
20
21 int Axy(int x,int y){
22 int res =1;
23 if(y==0)
24 return 1;
25 while(y--){
26 res *= x;
27 x--;
28 }
29 return res;
30 }
31
32 void solve(int count){
33 bool vis[16]={0},head = false;
34 int uselen = 0,countv;
35 for(int i=1;i<=8;i++){
36 int cnt = 15;
37 while(cnt){
38 if(!vis[cnt]){
39 if((countv = Axy(16-1-uselen,8-i))<count){
40 count -= countv;
41 }else{
42 vis[cnt] = true;
43 break;
44 }
45 }
46 cnt--;
47 }
48 ans[i] = num[cnt];
49 if(head||ans[i]!=‘0‘) uselen++;
50 if(ans[i]!=‘0‘) head = true;
51 }
52 }
53
54 int main()
55 {
56 int cnt;
57 while(cin>>cnt){
58 bool head = false;
59 solve(cnt);
60 for(int i=1;i<=8;i++){
61 if(head||ans[i]!=‘0‘){ //去除前导0
62 cout<<(char)ans[i];
63 head = true;
64 }
65 }
66 if(!head) // 若全为0 ,则输出0
67 cout<<0;
68 cout<<endl;
69 }
70 return 0;
71 }
poj 1715 Hexadecimal Numbers 排列组合
时间: 2024-10-11 08:10:17