[CF1073E]Segment Sum
阿新 • • 發佈:2018-11-05
題目大意:給定$K,L,R$,求$[L,R]$之間最多不包含超過$K$種數字的數的和。
題解:數位$DP$,令$f_{i,j}$為選到第$i$個數,已經用了的數字狀態為$j$,令$nxt$為當前條件的後面的數,$f_{i,j}=\sum\limits_{nxt}(d\times10^i+nxt)(d為當前這一位填的數)$,$f_{i,j}=d\times10^i\sum_{nxt}1+\sum_{nxt}nxt$
可以記錄$\sum nxt^0$和$\sum nxt^1$轉移即可
卡點:無
C++ Code:
#include <cstdio> const int mod = 998244353; int tot, num[20]; long long k, l, r; inline void up(long long &a, long long b) {if ((a += b) >= mod) a -= mod;} struct node { long long cnt, sum; } f[20][1 << 10]; long long pw[20]; node calc(int x, int lim, int S) { if (!x) return (node) {1, 0}; if (!lim && ~f[x][S].cnt) return f[x][S]; node F = (node) {0, 0}; for (int i = lim ? num[x] : 9; ~i; i--) { int nxt; if (!S && !i) nxt = 0; else nxt = S | 1 << i; if (__builtin_popcount(nxt) > k) continue; node tmp = calc(x - 1, lim && i == num[x], nxt); up(F.cnt, tmp.cnt); up(F.sum, (tmp.sum + tmp.cnt * pw[x - 1] % mod * i) % mod); } if (!lim) f[x][S] = F; return F; } long long solve(long long x) { tot = 0; while (x) { num[++tot] = x % 10; x /= 10; } return calc(tot, 1, 0).sum; } int main() { __builtin_memset(f, -1, sizeof f); scanf("%lld%lld%lld", &l, &r, &k); pw[0] = 1; for (int i = 1; i < 20; i++) pw[i] = pw[i - 1] * 10 % mod; printf("%lld\n", (solve(r) - solve(l - 1) + mod) % mod); return 0; }