现在有"abcdefghijkl”12个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的?
3 abcdefghijkl hgebkflacdji gfkedhjblcia
1 302715242 260726926
康托展开和逆康托展开,昨天看到这两道题,以前没有接触过的内容,看了一下介绍,就着手把这两道题给a了,感觉属于简单的数学题吧,数学题主要是要对这些概念公式要熟悉,然后按照公式应该就能够很快解决了。看资料上说康托展开最大最明显的作用就是在判断状态是否重复方面了,其实属于hash的一个技巧。(感觉还没深入到这种境界,还只能算是了解吧)
简单的介绍一下康托展开吧:
#include <stdio.h> #include <string.h> long long sum[15]={1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600}; int main() { int n; //char s[12]={'a','b','c','d','e','f','g','h','i','j','k','l'}; char c[12]; scanf("%d",&n); while(n--) { long long num=0; memset(c,0,sizeof(c)); scanf("%s",c); for(int i=0;i<12;i++) { long long temp=0; for(int j=i+1;j<12;j++) { if(c[j]<c[i])temp++;//这里就是判断后面有多少个数比本身小; } num+=temp*sum[12-i-1]; } printf("%lld\n",num+1); } return 0; }
3 1 302715242 260726926
abcdefghijkl hgebkflacdji gfkedhjblcia
这道题和上面的题测试数据是一样的,就是逆康托展开,相当于前面的逆运算。
下面是143的代码:
#include <stdio.h> #include <string.h> #define N 12 long long sum[15]={1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600}; int main() { int n,i,j,id; long int m,temp; char s[N+1];//这里先前我把数组开成12,然后中间就总不对,第一组数据的k都打印不出,不知道什么情况。 char c[13]={'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'}; scanf("%d",&n); while(n--) { scanf("%ld",&m); memset(s,0,sizeof(s)); strcpy(s,c); temp=m-1; for(i=0;i<N;i++) { id=temp/sum[N-i-1]; printf("%c",s[id]); for(j=id;j<N-i;j++) s[j]=s[j+1]; temp-=id*sum[N-i-1]; } printf("\n"); } return 0; }