题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6628
傻了 比赛中被卡死的一道题
方法:全排列+预处理 (next_permutation)
思路:将n分成大于9和小于等于9两种情况 大于9时 直接使用全排列函数对前K个进行排列即可得出答案,这个是一般情况
小于9时 因为最前面两个数不是按照一般情况的排列顺序,而是按照(n,1/n,2/n-1,1/n,3/n-1,2/n-2,1/.......)的情况,所以进行预处理 9!也就4W 预处理还是很快的
预处理思路:因为全排列不能根据两者之差进行全排列,用一个字符串存储两两之差,先处理出所有全排列,然后根据字符串大小,也就是两两之差的字典序大小用sort进行排序。
//
这里是重点
以上的思路是借鉴别人的 跑出来结果的是200ms 差强人意
于是接下来我进行了优化 发现当N=9时 因为k<10000 而7!=5040 ,因此N=9时的第二位最多也就是2,符合一般情况(这里有点说不清楚,QAQ,读者可以自己证明一下,可以参考上面的特殊情况的排列顺序)
于是预处理只处理到8为止,速度大幅上升
31ms是处理到8,200ms处理到9。
图片说明
//
直接上代码

#include <iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=4e5+10;
const int INF = 0x3f3f3f3f;
int t,n,k;
struct node{
    int x[11];
    char y[11];
}a[11][maxn];
int cmp(node aa,node bb){
    return strcmp(aa.y,bb.y)<0;
}
void init(){ // 预处理 处理出n小于9的情况
    a[1][1].x[0]=1;
    a[2][1].x[0]=2;
    a[2][1].x[1]=1;
    a[2][2].x[0]=1;
    a[2][2].x[1]=2;
    int b[9]={1,2,3,4,5,6,7,8,9};
    for(int k=3;k<9;k++){    
        int cnt=0;
        do{
            cnt++;
            for(int i=0;i<k;i++){
                a[k][cnt].x[i]=b[i];
                if(i) a[k][cnt].y[i-1]=a[k][cnt].x[i]-a[k][cnt].x[i-1]+'A';
            }
        }while(next_permutation(b,b+k));
        sort(a[k]+1,a[k]+cnt+1,cmp);
    }
}
int main(){
    init();
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&k);
        if(n>=9){//if n大于等于9
            int b[30];
            b[0]=n;
            for(int i=1;i<n;i++){
                b[i]=i;
            }
            do{
                k--;
                if(k==0) break;
            }while(next_permutation(b,b+n));
            for(int i=0;i<n;i++){
                if(i) printf(" ");
                printf("%d",b[i]);
            }
            printf("\n");
            continue;
        }
        for(int i=0;i<n;i++){//else n小于9
            if(i) printf(" ");
            printf("%d",a[n][k].x[i]);
        }
        printf("\n");
    }
}

//是不是觉得这种解法太麻烦
接下来是梦月巨佬的解法。。。看完我只能说 tql
(只有1W种方法,于是直接暴搜,搜的是相对值而不是绝对值)

#include <iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=100010;
const int INF = 0x3f3f3f3f;
int t,n;
int k;
int vis[110];
int ans[110];
bool dfs(int pos,int low,int hi){//low hi 代表最低和最高值,这里的值都是相对值,在输出时要减掉对应的值
    if(pos==n){
        k--;
        if(!k){
            for(int i=0;i<n;i++){
                if(i) printf(" ");
                printf("%d",ans[i]-low+1);//减掉对应值
            }
            printf("\n");
            return 1;
        }
        return 0;
    }
    for(int i=hi-n+1;i<=low+n-1;i++){
        if(vis[i]) continue;
        ans[pos]=i;
        vis[i]=1;
        if(dfs(pos+1,min(low,i),max(hi,i))){
            return 1;
        } 
        vis[i]=0;
    }
    return 0;
}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&k);
        memset(vis,0,sizeof(vis));
        ans[0]=n;
        vis[n]=1;
        dfs(1,n,n);
        vis[n]=0;
    }
} 

不难理解,但令人惊叹 这就是大佬⑧
只用了15MS。。。
我好菜啊