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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值