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]++;
        }
    }
}

 

posted @ 2016-12-21 18:52  Saurus  阅读(627)  评论(0编辑  收藏  举报