• Codeforces Round #387 (Div. 2) 747F(数位DP)


    题目大意

    给出整数k和t,需要产生一个满足以下要求的第k个十六进制数

    即十六进制数每一位上的数出现的次数不超过t

    首先我们先这样考虑,如果给你了0~f每个数字可以使用的次数num[i],如何求长度为L且满足要求的十六进制数有多少个

    dp[i][l]表示使用了前i个数字,已经将L的空位填上了l个的数有多少个

    转移方程 dp[i][l] = sigma(dp[i-1][l-j]*C[len-l+j[j]) 其中j是枚举填新的数的个数,C是组合数(选出j个空位填上新数)

    有了这个dp后,现在的问题就变成了找出第k个数

    首先先确定位数,枚举位数,然后就可以找到第k个数的位数是多少

    然后对从最高位开始枚举,确定每一位应该是多少

    最后就可以得出答案

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    typedef long long LL;
    const int maxl = 200;
    LL C[maxl][maxl], dp[16][maxl];
    int num[16], t;
    LL k;
    void prepare()
    {
        for(int i = 0; i < maxl; i++) C[i][0] = 1;
        for(int i = 1; i < maxl; i++)
            for(int j = 1; j <= i; j++)
                C[i][j] = C[i-1][j] + C[i-1][j-1];
    }
    
    LL solve(int len)
    {
        memset(dp, 0, sizeof(dp));
        for(int i = 0; i <= num[0]; i++) dp[0][i] = C[len][i];
        for(int i = 1; i < 16; i++)
            for(int l = 0; l <= len; l++)
                for(int j = 0; j <= min(num[i], l); j++)
                    dp[i][l] += dp[i-1][l-j]*C[len-l+j][j];
        return dp[15][len];
    }
    void print(int j)
    {
        if(j < 10) cout<<j;
        else cout<<(char)(j+'a'-10);
    }
    int main()
    {
        prepare();
        cin>>k>>t;
        for(int i = 0; i < 16; i++) num[i] = t;
        int len = 1;
        for(;; len++)
        {
            LL tmp = 0;
            if(len == 1) tmp = 15;
            else
                for(int j = 1; j < 16; j++)
                {
                    num[j]--;
                    tmp += solve(len-1);
                    num[j]++;
                }
            if(k > tmp) k -= tmp;
            else break;
        }
        for(int i = len; i > 0; i--)
        {
            if(i == 1)
            {
                for(int j = 0; j < 16; j++)
                {
                    if(j == 0 && len == 1) continue;
                    if(num[j] != 0) k--;
                    if(k == 0) { print(j); break; }
                }
                break;
            }
            for(int j = 0; j < 16; j++)
            {
                if(i == len && j == 0) continue;
                num[j]--;
                LL tmp = solve(i-1);
                if(k > tmp) k -= tmp;
                else
                {
                    print(j);
                    break;
                }
                num[j]++;
            }
        }
    }
  • 相关阅读:
    BZOJ 1072: [SCOI2007]排列perm
    BZOJ 1071: [SCOI2007]组队
    HDP集群部署
    使用Kubeadm部署kubernetes集群
    Docker 私有仓库
    Docker Compose
    Dockerfile使用
    Docker应用部署(Mysql、tomcat、Redis、redis)
    Docker 容器的数据卷 以及 数据卷容器
    Docker 服务、镜像、容器简单命令使用
  • 原文地址:https://www.cnblogs.com/Saurus/p/6208757.html
Copyright © 2020-2023  润新知