I - Ignatius and the Princess II

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1027

题解:

第一个数代表着1到n的从小到大的数列,如果n=10,就代表{1,2,3,4,5,6,7,8,9,10}这样的数组,第二个数代表第k小的排列,最后输出就行了。比如{1,2,3,4} 第1小的数列是{1,2,3,4},第二小的数列是{1,2,4,3},方法有两个:

1. 使用next_permutation()函数:

使用时第一个参数代表首地址,第二个参数代表尾地址,比如next_permutation(a,a+n).求第M小的数列,只要让原来从小到大的数列执行m-1次next_permutation()函数即可,这题使用这个方法完全可以AC,只要93ms,但是数据范围如果很大就会超时。就像蔡老师说的“程序员是很懒的”,在使用函数能解决的情况下,就使用这个函数A题。

2.使用阶乘的思想

比如1到100   改变24次(4的阶乘) ,只会对后(4+1)位数字发生变化,前面95个数字依旧不会改变,具体思路见下图:

 

 

 


 


 

纯手打,有疑问联系我

AC代码1:(用阶乘讨论)

#include<stdio.h>  

#include<string.h>  

int a[10]={1,1,2,6,24,120,720,5040};  

int b[10];  

int main ()  

{  

    int n,m,i,k,t;  

    while(scanf("%d%d",&n,&m)!=EOF)  

    {  

        for(i=1;i<=n-8;i++)  

            printf("%d ",i);  

        for(k=0;i<=n;i++)  

                b[k++]=i;  

        for(i=n>8?8:n;i>1;i--)  

        {  

            t=(m-1)/a[i-1];  

            for(k=0;k<8&&k<n;k++)  

            {  

                if(b[k]&&t==0)  

                {  

                    printf("%d ",b[k]);  

                    b[k]=0;  

                    break;  

                }  

                else if(b[k])  

                    t--;  

            }  

            m=(m-1)%a[i-1]+1;  

        }  

        for(k=0;k<8&&k<n;k++)  

                if(b[k])  

                    printf("%d\n",b[k]);  

          

    }  

    return 0;  

}

AC代码2:(用函数解决)

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

using namespace std;

#define N 1047

int num[N];

int main()

{

int n , m , i ,k;

while(~scanf("%d%d",&n,&m))

{

memset(num,0,sizeof(num));

for(i = 0 ; i < n ; i++)

{

num[i] = i+1;

}

for(i = 1 ; i < m ; i++)

{

next_permutation(num,num+n);

}

for(i = 0 ; i < n-1 ; i++)

printf("%d ",num[i]);

printf("%d\n",num[n-1]);

}

return 0;

}


猜你喜欢

转载自blog.csdn.net/qq_41464123/article/details/80584899