Codeforces1073E Segment Sum 【数位DP】

题目分析:

裸的数位DP,注意细节。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3
 4 const int mod = 998244353;
 5 int k;
 6
 7 int dp[25][1024],sz[25][1024],cnt[25][1024];
 8 int pw10[25],hp[25],num;
 9
10 int dfs(int now,int lst){
11     if(now == 0) return 0;
12     int ans = 0;
13     for(int i=0;i<hp[now];i++){
14     for(int j=0;j<(1<<10);j++){
15         int pp = (lst==0&&i==0?0:(1<<i));
16         int z = __builtin_popcount(j|pp|lst);
17         if(z > k) continue;
18         ans += 1ll*sz[now-1][j]*pw10[now-1]%mod*i%mod; ans %= mod;
19         ans += dp[now-1][j]; ans %= mod;
20     }
21     }
22     if(now == num){
23     for(int i=1;i<num-1;i++){
24         for(int j=0;j<(1<<10);j++){
25         int z = __builtin_popcount(j);
26         if(z > k) continue;
27         z = __builtin_popcount(j|1);
28         if(z <= k) continue;
29         ans += dp[i][j]; ans %= mod;
30         }
31     }
32     }
33     for(int i=0;i<(1<<10);i++){
34     int z = __builtin_popcount(i|(1<<hp[now])|lst);
35     if(z > k) continue;
36     ans += 1ll*cnt[now-1][i]*pw10[now-1]%mod*hp[now]%mod;
37     ans %= mod;
38     }
39     ans += dfs(now-1,lst|(1<<hp[now]));
40     ans %= mod;
41     return ans;
42 }
43
44 int solve(long long now){
45     num = 0;
46     memset(cnt,0,sizeof(cnt));cnt[0][0] = 1;
47     while(now){hp[++num] = now%10;now /= 10;}
48     for(int i=1;i<=num;i++){
49     for(int j=0;j<hp[i];j++){
50         for(int k=0;k<(1<<10);k++){
51         cnt[i][k|(1<<j)] += sz[i-1][k];
52         cnt[i][k|(1<<j)] %= mod;
53         }
54     }
55     for(int k=0;k<(1<<10);k++){
56         cnt[i][k|(1<<hp[i])] += cnt[i-1][k];
57         cnt[i][k|(1<<hp[i])] %= mod;
58     }
59     }
60     return dfs(num,0);
61 }
62
63 int main(){
64     long long l,r;
65     cin >>l >> r >> k;
66     sz[0][0] = 1;pw10[0] = 1;
67     for(int i=1;i<=20;i++) pw10[i] = 1ll*pw10[i-1]*10%mod;
68     for(int i=1;i<=20;i++){
69     for(int f = 1;f<=9;f++){
70         for(int j=0;j<(1<<10);j++){
71         sz[i][j|(1<<f)] += sz[i-1][j]; sz[i][j|(1<<f)]%=mod;
72         dp[i][j|(1<<f)] += dp[i-1][j]; dp[i][j|(1<<f)] %= mod;
73         dp[i][j|(1<<f)] += 1ll*sz[i-1][j]*pw10[i-1]%mod*f%mod;
74         dp[i][j|(1<<f)] %= mod;
75         for(int k=0;k<i-1;k++){
76             sz[i][j|(1<<f)|1] += sz[k][j]; sz[i][j|(1<<f)|1]%=mod;
77             dp[i][j|(1<<f)|1] += dp[k][j]; dp[i][j|(1<<f)|1]%=mod;
78             dp[i][j|(1<<f)|1] += 1ll*sz[k][j]*pw10[i-1]*f%mod;
79             dp[i][j|(1<<f)|1] %= mod;
80         }
81         }
82     }
83     }
84     for(int i=1;i<=20;i++){
85     for(int j=0;j<(1<<10);j++){
86         sz[i][j|1] += sz[i-1][j];
87         dp[i][j|1] += dp[i-1][j];
88         sz[i][j|1] %= mod; dp[i][j|1] %= mod;
89     }
90     }
91     long long ans = solve(r)-solve(l-1);
92     ans+=mod; ans %= mod;
93     cout<<ans<<endl;
94     return 0;
95 }

原文地址:https://www.cnblogs.com/Menhera/p/9901921.html

时间: 2024-10-06 01:19:19

Codeforces1073E Segment Sum 【数位DP】的相关文章

CodeForces - 1073E :Segment Sum (数位DP)

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

E. Segment Sum(数位dp)

题意:求一个区间内满足所有数位不同数字个数小于K的数字总和.比如:k=2   1,2,3所有数位的不同数字的个数为1满足,但是123数位上有三个不同的数字,即123不满足. 我们可以使用一个二进制的数字来记录某个数字是否已经出现,0为还没有出现,1表示该数字已经出现了.这里还需要注意前导零的干扰. #include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include

zoj 3962 Seven Segment Display(数位dp)

Seven Segment Display Time Limit: 2 Seconds      Memory Limit: 65536 KB A seven segment display, or seven segment indicator, is a form of electronic display device for displaying decimal numerals that is an alternative to the more complex dot matrix

ACdreamOJ 1154 Lowbit Sum (数位dp)

ACdreamOJ 1154 Lowbit Sum (数位dp) ACM 题目地址:ACdreamOJ 1154 题意: long long ans = 0; for(int i = 1; i <= n; i ++) ans += lowbit(i) lowbit(i)的意思是将i转化成二进制数之后,只保留最低位的1及其后面的0,截断前面的内容,然后再转成10进制数.即lowbit(i) = i&(-i). 每输入一个n,求ans 分析: 用二进制去考虑,可以发现这是个数位dp,如果当前第i

CF1073E Segment Sum 解题报告

CF1073E Segment Sum 题意翻译 给定\(K,L,R\),求\(L~R\)之间最多不包含超过\(K\)个数码的数的和. \(K\le 10,L,R\le 10^{18}\) 数位dp \(dp_{i,s}\)前\(i\)位出现集合\(s\)的贡献和和出现次数 然后记忆化的时候转移一下就行了 然而写的时候还是怪麻烦的 Code: #include <cstdio> #include <cstring> #define ll long long const int mo

51Nod 1009 数字1的个数 | 数位DP

题意: 小于等于n的所有数中1的出现次数 分析: 数位DP 预处理dp[i][j]存 从1~以j开头的i位数中有几个1,那么转移方程为: if(j == 1) dp[i][j] = dp[i-1][9]*2+pow(10,i-1);else dp[i][j] = dp[i-1][9]+dp[i][j-1]; 然后注意下对于每个询问统计的时候如果当前位为1需要额外加上他后面所有位数的个数,就是n%pow(10,i-1); 这样总复杂度log(n)*10 #include <bits/stdc++.

数位dp

1.[hdu3709]Balanced Number 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cstdlib> 6 #include<algorithm> 7 #include<ctime> 8 #include<cmath> 9 #include<queue>

LightOJ1068 Investigation(数位DP)

这题要求区间有多少个模K且各位数之和模K都等于0的数字. 注意到[1,231]这些数最大的各位数之和不会超过90左右,而如果K大于90那么模K的结果肯定不是0,因此K大于90就没有解. 考虑到数据规模,数据组数,这题状态这么表示: dp[i][j][k]:位数为i模K结果为j且各位数之和模K结果为k的数字个数 然后就是转移方程,最后就是统计.. 统计部分好棘手...半乱搞下AC的..还是对数位DP的这一部分太不熟悉了. 1 #include<cstdio> 2 #include<cstr

HDU 4734 F(x)(数位DP)

Description For a decimal number x with n digits (A nA n-1A n-2 ... A 2A 1), we define its weight as F(x) = A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there betwe