1. 程式人生 > >Codeforces 1073E——狀壓+數位dp

Codeforces 1073E——狀壓+數位dp

題意

輸入l r k,輸出區間[l,r]內數位種數不超過k的數字之和,比如l=10,r=50,k=1,答案就是11+22+33+44=110

1<=l<=1e18,1<=e<=1e18,1<=k<=9

思路

比較明顯的數位dp,因為要考慮當前所用的數位種類所以要把用過的數位狀壓一下,用dp[i][s]表示從低到高遞推到第i位,所用的數位集合為s時的數字個數,數字之和另外開一個數組dp2[i][s]進行記錄,計算數字之和的時候只要用數字個數乘上當前選擇的數位再乘上相應的10的冪次就可以了,注意取模,尤其是最後solve(r)-solve(l-1)的減法取模

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
int k;
ll a[20], dp[20][1500], dp2[20][1500], res[20][1500];
ll dfs(int pos, int state, int limit, int lead) {
    if (pos == 0 && state == 1 && lead) return 1;
    if (state == 0 && pos != 0) return 0;
    if (pos == 0) {
        if (state == 0) return 1;
        else return 0;
    }
    if (!limit && !lead && dp[pos][state] != -1) {
        res[pos][state] = dp2[pos][state];
        return dp[pos][state];
    }
    ll ans = 0;
    int down = 0, up = limit ? a[pos] : 9;
    if (lead) {
        down = 1;
        ans = (ans + dfs(pos-1, state, 0, 1)) % mod;
        res[pos][state] = res[pos-1][state];
    }
    else {
        res[pos][state] = 0;
    }
    for (int i = down; i <= up; i++) {
        if (state & (1<<i)) {
            ll t1 = dfs(pos-1, state, limit && i == a[pos], lead && i == 0);
            ll t2 = dfs(pos-1, state^(1<<i), limit && i == a[pos], lead && i == 0);
            ans = (ans + t1 + t2) % mod;
            ll t = (t1 + t2) % mod * i % mod;
            for (int j = 1; j <= pos-1; j++) t = t * 10LL % mod;
            res[pos][state] = (res[pos][state]+res[pos-1][state]+res[pos-1][state^(1<<i)]+t) % mod;
        }
    }
    if (!limit && !lead) {
        dp[pos][state] = ans;
        dp2[pos][state] = res[pos][state];
    }
    return ans;
}
ll solve(ll x) {
    if (x == 0) return 0;
    int cnt = 0;
    while (x) {
        a[++cnt] = x % 10;
        x /= 10;
    }
    memset(dp, -1, sizeof(dp));
    memset(dp2, 0, sizeof(dp2));
    memset(res, 0, sizeof(res));
    ll ans = 0;
    for (int i = 1; i < (1<<10); i++) {
        int t = 0;
        for (int j = 0; j < 10; j++) if (i & (1<<j)) t++;
        if (t <= k) {
            dfs(cnt, i, 1, 1);
            ans = (ans + res[cnt][i])%mod;
        }
    }
    return ans;
}
int main() {
    ll l, r;
    scanf("%I64d%I64d%d", &l, &r, &k);
    printf("%I64d\n", (solve(r) - solve(l-1) + mod) % mod);
    return 0;
}