转载请注明出处:http://blog.csdn.net/lttree
6 4 11 8
1 2 3 5 6 4 1 2 3 4 5 6 7 9 8 11 10
这道题,题意就是求 N的第m种排列。
应该属于组合数学中的一种,刚好之前做过康托展开,就感觉可以用康托展开来做。
(康拓展开详情可戳→http://blog.csdn.net/lttree/article/details/24798653)
但是,我看了看数据范围就被吓到了, N and M(1<=N<=1000, 1<=M<=10000)。
阶乘,最多只是10,怎么N可以到1000.。。。
仔细一想就可以发现,M最大为10000,也就是说,最多也就只有后面8个数才会动。前面不会动的。
因为1~8的阶乘为:1,2,6,24,120,720,5040,40320.
8的阶乘为40320>10000 10000种以内的排列序,只能在最后8个变化。
换种说法,无论N为多少,当N>8时,前N-8是不变的,只有后面8个在变化。
例如:N为11,那么前面3个数为1 2 3顺序一定不变,变化的永远是后面4~11
思路想出来后,解决这道题就不算太难。
本来我用的是,边算遍输出,但是总是PE,可能还是有地方没想到吧。
就直接将答案存在一个ans数组里,最后一起输出,就AC了。
/**************************************** ***************************************** * Author:Tree * *From :http://blog.csdn.net/lttree * * Title : Ignatius and the Princess II * *Source: hdu 1027 * * Hint : 康托展开 * ***************************************** ****************************************/ #include <iostream> using namespace std; int fac[]={1,1,2,6,24,120,720,5040,40320}; // 存储答案 int ans[10001],len; // 康托展开的逆 n为要对几位数排序,k为第几个数,num为这n个数应该从多少开始 void reverse_kangtuo(int n,int k,int num) { int i, j, t, vst[11]={0}; char s[11]; --k; for (i=0; i<n; i++) { t = k/fac[n-i-1]; for (j=1; j<=n; j++) if (!vst[j]) { if (t == 0) break; --t; } s[i] = '0'+j; vst[j] = 1; k %= fac[n-i-1]; } // 排序后的赋给答案数组 for(int kk=0;kk<n;++kk) ans[len++]=s[kk]-'1'+num; } int main() { int n,m; int i,j,temp1,temp2; while( cin>>n>>m ) { i=1; len=0; if( n>8 ) { temp1=n%8; temp2=(n/8-1)*8; // 相应答案赋值 for(;i<=temp1;++i) ans[len++]=i; for(j=0;j<temp2;++j,++i) ans[len++]=i; reverse_kangtuo(8,m,i); } else reverse_kangtuo(n,m,i); // 输出,注意最后一个数后面没有空格 for(i=0;i<len-1;++i) cout<<ans[i]<<" "; cout<<ans[len-1]<<endl; } return 0; }