E. Segment Sum

E. Segment Sum

You are given two integers l and r (lr). Your task is to calculate the sum of numbers from l to r (including l and r) such that each number contains at most k different digits, and print this sum modulo 998244353.

For example, if k=1 then you have to calculate all numbers from l to r such that each number is formed using only one digit. For l=10,r=50 the answer is 11+22+33+44=110.

Input

The only line of the input contains three integers l, r and k (1lr<1018,1k10) — the borders of the segment and the maximum number of different digits.

Output

Print one integer — the sum of numbers from l to r such that each number contains at most k different digits, modulo 998244353.

Examples

input

10 50 2

output

1230

input

1 2345 10

output

2750685

input

101 154 2

output

2189

Note

For the first example the answer is just the sum of numbers from l to r which equals to 505129102=1230. This example also explained in the problem statement but for k=1.

For the second example the answer is just the sum of numbers from l to r which equals to 234523462=2750685.

For the third example the answer is 101+110+111+112+113+114+115+116+117+118+119+121+122+131+133+141+144+151=2189.

 

解题思路

  今天写专门挑了几道数位 dp 的题目来做,选这题来写篇题解吧。

  定义 dp(N) 表示前 N 个数中满足十进制下最多有 k 个不同数字的数的总和,因此答案就是 dp(r)dp(l1)

  由于需要知道某个数用了哪些数字,因此必然会用到状态压缩。定义状态 f(i,j,k,u) 表示满足以下条件的数(用 n 来表示)的总和

  • n 的数位大小为 i,即满足 0n<10i
  • nNmod10i,则 j=1,否则 j=0
  • n 的最高位是 0,则 k=1,否则 k=0
  • nu 的二进制下为 1 的位所对应的数字构成,例如 u=(10011)2,那么 n 由数字 014 构成。

  在得到状态转移方程前,还需要再定义状态 g(i,j,k,u) 表示满足以上相同条件的数(用 n 来表示)的数量

  当确定了状态 f(i,j,k,u)g(i,j,k,u) 后,就可以转移到数位大小为 i+1 的状态,根据第 i+1 位是哪个数字 v 来进行状态划分,有状态转移方程

f(i,j,k,u)+v10ig(i,j,k,u)f(i+1,[v<piorv=piandj],[!v],u2v)

g(i,j,k,u)g(i+1,[v<piorv=piandj],[!v],u2v)

  其中 pi 就是 N 在十进制下的第 i 位(从右往左,最低位为第 0 位)。假设 N 在十进制下有 sz 位,count(x) 表示 x 在二进制下 1 的个数,那么最终答案就是dp(N)=i=1szj=12101[count(j)m]f(i,1,0,0)+i=1sz1j=12101[count(j)m]f(i,0,0,0)

  AC 代码如下,时间复杂度为 O(210logN)

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 25, M = 1 << 10, mod = 998244353;

LL l, r;
int m;
int p[N], sz;
int q[N];
int f[N][2][2][M], g[N][2][2][M];

int get(LL x) {
    if (!x) return 0;
    sz = 0;
    while (x) {
        p[sz++] = x % 10;
        x /= 10;
    }
    q[0] = 1;
    for (int i = 1; i < sz; i++) {
        q[i] = q[i - 1] * 10ll % mod;
    }
    memset(f, 0, sizeof(f));
    memset(g, 0, sizeof(g));
    g[0][1][0][0] = 1;
    for (int i = 0; i < sz; i++) {
        for (int j = 0; j <= 1; j++) {
            for (int k = 0; k <= 1; k++) {
                for (int u = 0; u < M; u++) {
                    for (int v = 0; v <= 9; v++) {
                        int &x = f[i + 1][v < p[i] || v == p[i] && j][!v][u | 1 << v];
                        int &y = g[i + 1][v < p[i] || v == p[i] && j][!v][u | 1 << v];
                        x = (x + 1ll * v * q[i] * g[i][j][k][u] + f[i][j][k][u]) % mod;
                        y = (y + g[i][j][k][u]) % mod;
                    }
                }
            }
        }
    }
    int ret = 0;
    for (int i = 1; i <= sz; i++) {
        for (int j = 1; j < M; j++) {
            if (__builtin_popcount(j) <= m) {
                ret = (ret + f[i][1][0][j]) % mod;
                if (i < sz) ret = (ret + f[i][0][0][j]) % mod;
            }    
        }
    }
    return ret;
}

int main() {
    scanf("%lld %lld %d", &l, &r, &m);
    printf("%d\n", (get(r) - get(l - 1) + mod) % mod);
    
    return 0;
}

 

参考资料

  Educational Codeforces Round 53 Editorial:https://codeforces.com/blog/entry/62742

posted @   onlyblues  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2022-10-25 E. FTL
Web Analytics
点击右上角即可分享
微信分享提示