HDU 1027 Ignatius and the Princess II【求第M个排列】

来源:互联网 发布:php授权验证系统 编辑:程序博客网 时间:2024/05/24 06:27

题意:求1-n的按升序规则的第M个排列,如1243是N=4的第2个排列,1324是第3个,即第M小序列

法①:康托展开逆运算求全排列,直接求的话会因为N最大是1002,需要打表出1002个阶乘不好。

因为8!> 10000(M最大值),即8个位足够表示1W种情况,所以此题改变的一定是1-n的后8位。即前n-8位一定是1,2,3,……n-8,而后8位只需要正常求出1-8的第M个排列,然后这些数都加上1-n排序后的倒数第9位。如:

对于1 2 3 4 5 6 7 8 9 10,M=2

1和2肯定不会被改变到,所以求1-8的第2个全排列:1 2 3 4 5 6 8 7,然后这些数加2就是后8位

#include<cstdio>#include<cmath>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#define ll long long#define NMAX 500001#define FOR(i,n) for(int i=0;i<n;i++)int fac[]={1,1,2,6,24,120,720,5040,40320,362880,3628800};void f(int n, int k, int s[]){    int i, j, t, vst[1002]={0};    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] = j;        vst[j] = 1;        k %= fac[n-i-1];    }}int main(){int n,m,count,former;int a[1002];while( scanf("%d%d",&n,&m)!=EOF)    {        if(n > 8)        {            former = n - 8;            count = 1;            for(int i=1;i<=former;i++)                printf("%d ",count++);            f(8,m,a);            count--;            for(int i=0;i<7;i++)                printf("%d ",a[i]+count);            printf("%d\n",a[7]+count);        }        else        {            f(n,m,a);            for(int i=0;i<n-1;i++)                printf("%d ",a[i]);            printf("%d\n",a[n-1]);        }}return 0;}
也可以直接用C++库 next_permutation(起点地址,终点地址)函数,

如 next_permutation(a,a+n);则a数组会变成1-n的下一个排列,注意求第M个排列,运行M-1次即可,因为一开始a数组必须是排序后的(第1个排列)

#include<cstdio>#include<cmath>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#define ll long long#define NMAX 500001#define FOR(i,n) for(int i=0;i<n;i++)//next_permutation(address_begin,adress_end)int main(){int n,m;int a[1002];while( scanf("%d%d",&n,&m)!=EOF){for(int i=1;i<=n;i++)            a[i] = i;        for(int i=0;i<m-1;i++)//m-1 times            next_permutation(a+1,a+n+1);for(int i=1;i<n;i++)            printf("%d ",a[i]);         printf("%d\n",a[n]);}return 0;}



0 0