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;
    }
  • 相关阅读:
    [Leetcode] ZigZag Conversion
    [Leetcode] Wildcard Matching
    [Leetcode] 4Sum
    [Leetcode] Word Break II
    [Leetcode] Best Time to Buy and Sell Stock III
    [Leetcode] Permutation Sequence
    [Leetcode] Surrounded Regions
    [Jobdu] 题目1522:包含min函数的栈
    CUDA2.1-原理之索引与warp
    opencv8-GPU之相似性计算
  • 原文地址:https://www.cnblogs.com/isakovsky/p/11305964.html
Copyright © 2011-2022 走看看