2019hdu暑假多校训练赛第五场1005 permutation 1 hdu 6628(全排列)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6628

题意:给定n和k,要求用1到n求出一个序列使得这个序列后一项减前一项形成的n-1长度的序列的字典序最小。

数据范围:1≤T≤40,2≤N≤20, 1≤K≤min(1e4,N!)

 

思路:首先字典序最小的序列一定是n,1,2,3.........n-2,n-1这样的。再考虑8的阶乘是40320,9的阶乘是362880,所以9以下的直接预处理全排列找出所有的可行解,排序,对于每次访问第k大的输出即可,对于9以上的,从10开始那么第一项和第二项就是固定的a[1]=n,a[2]=1,那么剩下的n-2项是大于等于8的,由于数据小于1e4所以全排列也不会影响到第二项的1,所以直接固定前两项,对于后面的n-2项全排列k次即可

 

#include 
using namespace std;
typedef long long ll;
const int N=4e5+5;
int n,m,t;
struct p{
    int num[11];
    char str[11];
}a[11][N];
bool cmp(p aa, p bb){
    return strcmp(aa.str,bb.str)<0;
}

int main(){
    int b[15]={0,1,2};
    for(int k=2;k<=9;k++){

        int cnt=1;
        do{
            for(int i=1;i<=k;i++){
                a[k][cnt].num[i]=b[i];
                if(i!=1)a[k][cnt].str[i-2]=b[i]-b[i-1]+'A';
            }
            a[k][cnt].str[k-1]='\0';
            cnt++;
        }while(next_permutation(b+1,b+k+1));

        sort(a[k]+1,a[k]+cnt,cmp);
        b[k+1]=k+1;
    }
    scanf("%d",&t);
    while(t--){
        int k;
        scanf("%d%d",&n,&k);
        if(n>9){
            int c[30];
            c[1]=n;
            for(int i=2;i<=n;i++)c[i]=i-1;
            for(int i=1;i

 

你可能感兴趣的:(acm算法学习)