Educational DP Contest S-Digit Sum(数位dp)

S - Digit Sum

原题链接:https://atcoder.jp/contests/dp/tasks/dp_s

题目大意:

给一个n,求从1到n的数中,所有位上的数字之和能被m整除的个数。

解题思路:

数位$dp$,建一个三维数组,$dp[i][j][k]$,其中,$i$代表第几位,j代表位数前i位位数之和对$m$取余的结果,$k$代表前i位是否已经是最大的数,如果已经是最大的,那$i+1$位就从$0$遍历到$n[i+1]$,否则就遍历到9。然后记忆化搜索。

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 #define debug(a) cout<<#a<<":"<<a<<endl;
 5 const ll INF=0x3f3f3f3f;
 6 const ll N=1e6+7;
 7 const ll mod=1e9+7;
 8 ll maxn,minn;
 9 ll T,n,m,k;
10 string s;
11 ll arr[N];
12 ll dp[10010][110][2];
13 
14 ll dfs(ll a,ll b,ll c){
15     ll d,ans=0,bb;
16     if(dp[a][b][c]!=-1){
17         return dp[a][b][c];
18     }
19     if(a==n+1){
20         if(b==0){
21             return dp[a][b][c]=1;
22         }
23         else{
24             return dp[a][b][c]=0;
25         }
26     }
27     if(c==1){
28         d=arr[a];
29     }
30     else{
31         d=9;
32     }
33     for(ll i=0;i<=d;i++){
34         bb=(b+i)%k;
35         dp[a+1][bb][c&(i==d)]=dfs(a+1,bb,c&(i==d));
36         ans=(ans+dp[a+1][bb][c&(i==d)])%mod;
37     }
38     return dp[a][b][c]=ans;
39 }
40 
41 int main(){
42     cin>>s>>k;
43     n=s.size();
44     for(ll i=1;i<=n;i++){
45         arr[i]=s[i-1]-'0';
46     }
47     memset(dp,-1,sizeof(dp));
48     
49     printf("%lld\n",(dfs(1,0,1)-1+mod)%mod);
50
51     return 0;
52 }

 

posted @ 2020-05-08 19:45  yya雨  阅读(375)  评论(0编辑  收藏  举报