转载请注明出处: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;
}
ACM-简单题之Ignatius and the Princess II——hdu1027,布布扣,bubuko.com
ACM-简单题之Ignatius and the Princess II——hdu1027
原文:http://blog.csdn.net/lttree/article/details/26244269