题目链接 hdu 6626
http://acm.hdu.edu.cn/showproblem.php?pid=6628
题意
你需要求一个长度为n的排列,使得这个排列的差分数组在所有差分数组中的字典序为第k大。
思路
8的阶乘为40320,9的阶乘为362880,K最大为1e4
1、对于 n 大于等于 9 的,答案肯定是 n 1 2 3 + 后八位 的形式,顶多只有最后八位会改变位置。
所以我们先按n 1 2 3 4 5 …… n-1的方式排(这样为题目中定义的字典序最小),然后对后八位直接暴力枚举全排列 K - 1次就可以得到答案。
2、而对于n小于9的,第一位不一定是n,所以我们枚举全排列,然后对全排列按照后一位减前一位的字典序进行排序,然后取第K个就OK。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 30;
const int size_ = 2e4 + 5;
struct node
{
int ans[maxn];
char s[maxn];
}a[maxn][size_];
bool cmp(node a, node b)
{
return strcmp(a.s, b.s) < 0;
}
void init()
{
int num[maxn] = {0, 1, 2};//从2开始
for(int len = 2; len <= 9; ++len)//预处理长度<=9 >=2的情况
{
int cnt = 0;//记录有几个排列
do{
++cnt;
for(int i = 1; i <= len; ++i)//在这个长度下,对于每一种排列
{
a[len][cnt].ans[i] = num[i];
if(i != 1)
a[len][cnt].s[i - 2] = num[i] - num[i - 1] + 'A';
}
a[len][cnt].s[len - 1] = '\0';
}while(next_permutation(num + 1, num + 1 + len));
//cout<<"dfa"<<endl;
sort(a[len] + 1, a[len] + 1 + cnt, cmp);
num[len + 1] = len + 1;
}
}
int main()
{
init();
int t;
scanf("%d", &t);
while(t--)
{
int n, k;
scanf("%d %d", &n, &k);
if(n >= 9)
{
int b[maxn];
b[1] = n;
for(int i = 1; i < n; ++i){
b[i + 1] = i;//最小的排列
}
for(int i = 1; i < k; i++){
next_permutation(b + 1, b + 1 + n);
}
for(int i = 1; i <= n; ++i){
i == 1 || printf(" ");
printf("%d", b[i]);
}
printf("\n");
continue;
}
for(int i = 1; i <= n; ++i)
{
i == 1 || printf(" ");
printf("%d", a[n][k].ans[i]);
}
printf("\n");
}
return 0;
}
参考来源
博客
https://blog.csdn.net/qq_43316231/article/details/98520452#commentsedit