zoukankan      html  css  js  c++  java
  • hdu多校第五场1005 (hdu6628) permutation 1 排列/康托展开/暴力

    题意:

    定义一个排列的差分为后一项减前一项之差构成的数列,求对于n个数的排列,差分的字典序第k小的那个,n<=20,k<=1e4。

    题解:

    暴力打表找一遍规律,会发现,对于n个数的排列,如果想找到差分的字典序第k小的,如果k<=(n-1)!,那么对应的那个排列就是把第一位赋值为n,后面的是1~n-1的元素本身排列字典序第k小的。

    比如,4个元素的排列的差分字典序最小的前6个分别是

    4,1,2,3

    4,1,3,2

    4,2,1,3

    4,2,3,1

    4,3,1,2

    4,3,2,1

    当n为10或更多的时候,(n-1)!>1e4,便可用康托逆展开直接计算。

    当n为9以下时,原先的想法是在本地暴力排序,对于每个n都取前1e4个元素交表。后来发现hdu限制提交代码大小,分析了一下,9!约等于3e5,暴力打表,过了。

    #include<iostream>
    #include<vector>
    #include<algorithm>
    #define LL long long
    using namespace std; 
    int MAXN;
    LL fact[25];
    int tmp[30];
    struct Node{
        int px[12];//排列
        int cha[12];//排列的差分
        int indexpx;
        int indexcha;
        friend bool operator > (const Node &a,const Node &b){
            for(int i=1;i<MAXN;i++){
                if(a.cha[i]!=b.cha[i])return a.cha[i]>b.cha[i];
            }
        }
        friend bool operator < (const Node &a,const Node &b){
            for(int i=1;i<MAXN;i++){
                if(a.cha[i]!=b.cha[i])return a.cha[i]<b.cha[i];
            }
        }
        //比较差分的字典序
    }node[10000000];
    int ans[10][100005];
    void make_ans(){
        for(int i=1;i<=MAXN;i++){
            node[1].px[i]=i;
            node[1].cha[i-1]=1;
        }
        node[1].indexpx=1;
        int i,n;
        for(i=2;;i++){
            for(int j=1;j<=MAXN;j++){
                node[i].px[j]=node[i-1].px[j];
            }
            if(!next_permutation(&node[i].px[1],&node[i].px[MAXN+1])){
                n=i-1;
                break;
            }
            
            for(int j=1;j<MAXN;j++){
                node[i].cha[j]=node[i].px[j+1]-node[i].px[j];
            }
            
            node[i].indexpx=i;
        }
        sort(node+1,node+1+n);
        for(int i=1;i<=min(n,10000);i++){
            ans[MAXN][i]=node[i].indexpx;
        }
        //暴力打表预处理
    }
    void make_fact(){
        fact[0]=1;
        for(int i=1;i<=20;i++){
            fact[i]=fact[i-1]*i;
        }
    }
    void Cantor_invexp(int *p,int len,LL rank){
        //康托逆展开
        int temp[len];
        for(int i=0;i<len;i++){
            temp[i]=i+1;
        }
        for(int i=1;i<=len;i++){
            int a=rank/fact[len-i];
            rank%=fact[len-i];
            for(int j=0;j<len;j++){
                if(a==0 && temp[j]>0){
                    p[i]=temp[j];
                    temp[j]=0;
                    break;
                }else if(temp[j]>0){
                    a--;
                }
            }
        }
        return ;
    }
    
    int main(){
        make_fact();
        for(int i=2;i<=9;i++){
            MAXN=i;
            make_ans();
        }
        
    //    return 0;
        int t;
        scanf("%d",&t);
        while(t--){
            int n,k;
            scanf("%d %d",&n,&k);
            if(n>=10){
                printf("%d",n);
                Cantor_invexp(tmp,n-1,1LL*k-1);
                for(int i=1;i<=n-1;i++){
                    printf(" %d",tmp[i]);
                }
                printf("
    ");
            }else{
                Cantor_invexp(tmp,n,1LL*ans[n][k]-1);
                for(int i=1;i<=n;i++){
                    printf("%d",tmp[i]);
                    if(i<n)printf(" ");
                    else printf("
    ");
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    HDU 2852 KiKi's K-Number (主席树)
    HDU 2089 不要62
    Light oj 1140 How Many Zeroes?
    Bless You Autocorrect!
    HDU 6201 transaction transaction transaction
    HDU1561 The more ,The better (树形背包Dp)
    CodeForces 607B zuma
    POJ 1651 Mulitiplication Puzzle
    CSUOJ 1952 合并石子
    Uva 1599 Ideal path
  • 原文地址:https://www.cnblogs.com/isakovsky/p/11305964.html
Copyright © 2011-2022 走看看