ABC 194 F.Digits Paradise in Hexadecimal

题意:给你一个数字n,让你求1-n之间,十六进制下恰好有k个不同数字的数有几个。

思路:一眼就看出了是数位dp。但是没有仔细去想非常的遗憾。赛后发现其实只需要用一个16位的01串去表示这个数字有没有被用过就行了。

个人喜欢用记忆化搜索写数位dp。给出dp数组。dp[16位的01串][当前枚举数位][是否有前导0][是否满足大小限制]

#include <bits/stdc++.h>
#define DEBUG if(0)
typedef long long ll;
using namespace std;

const int maxSz = 2e5, maxCnt = 16;
const ll mod = 1e9 + 7;
ll dp[maxSz][maxCnt + 1][2][2];

char s[maxSz + 1];
int a[maxSz];
int sz, k;

ll solve(int state, int pos, bool lmt, bool lead) {
    int cnt = __builtin_popcount(state);
    if (cnt > k) return 0;
    if (pos == sz) return cnt == k && lead;

    ll &ans = dp[pos][cnt][lmt][lead];
    if (ans != -1) return ans;

    ans = 0;
    int llmt = (lmt ? a[pos] : 15);
    for (int i = 0; i <= llmt; i++)
        ans = (ans + solve((!i && !lead) ? state : state | (1 << i), pos + 1, lmt & (i == llmt), lead | i)) % mod;
    return ans;
}

int main() {
    cin >> s >> k;
    sz = strlen(s);
    for (int i = 0; i < sz; i++) {
        a[i] = s[i] - (isdigit(s[i]) ? '0' : 'A' - 10);
    }
    memset(dp, -1, sizeof(dp));
    cout << solve(0, 0, 1, 0) << endl;

  return 0;
}
原文地址:https://www.cnblogs.com/Vikyanite/p/14498640.html