19杭电暑假多校 第五场 permutation 1(暴力)

题目链接 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值