[CF1073E]Segment Sum
题目大意:给定$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; }