[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;
}

浙公网安备 33010602011771号