hihoCoder 1033

题目链接:

http://hihocoder.com/problemset/problem/1033

听说这个题是xiaodao出的~~

我们要知道dp其实就是一个记忆化搜索的过程,如果某个子结构之前搜索过了,那么这次我们就不搜索了。

所以数位dp记录的其实就是dp[pos][state]pos位以内满足条件state的情况数。

当然,作为第二次做数位dp的渣渣,我觉得还是得强调几点:

1、一定要记录一个limit,代表这一位的取数是否受限制。

2、记录一个flag,代表之前的数是否都是前导0。

3、注意(!flag&&!limit)的情况下再给dp[pos][state]赋值。

剩下的好像就没啥了。。。dfs就行,注意递归结束条件。。。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 
  5 using namespace std;
  6 const int maxn = 20;
  7 const int maxs = 300;
  8 const long long mod = 1000000000 + 7;
  9 
 10 typedef long long int64;
 11 
 12 typedef struct Node{
 13   int64 cnt, sum;
 14 
 15   Node(){
 16     cnt = sum = 0;
 17   }
 18 
 19   Node( int64 cnt, int64 sum ){
 20      this->cnt = cnt;
 21      this->sum = sum;
 22   }
 23 
 24   Node(const struct Node& node){
 25     cnt = node.cnt;
 26     sum = node.sum;
 27   }
 28 }Node;
 29 
 30 Node dp[maxn][maxs][2];
 31 int64 l, r;
 32 int k;
 33 
 34 int64 c[maxn];
 35 int digit[maxn];
 36 
 37 void Init(void){
 38   c[0] = 1;
 39   for( int i = 1; i <= 18; ++i ){
 40     c[i] = (c[i-1] * 10)%mod;
 41   }
 42 }
 43 
 44 Node dfs( int pos, int sum, int p, int flag, int limit ){
 45   Node ans;
 46   if( sum < 0 || sum > 200 )
 47      return Node(0, 0);
 48 
 49   if( pos < 0 ){
 50     if(flag)
 51       ans.cnt = 0;
 52     else
 53       ans.cnt = (sum == 100) ? 1 : 0;
 54     ans.sum = 0;
 55     return ans;
 56   }
 57 
 58   if(!flag && !limit && dp[pos][sum][p].cnt != -1)
 59     return dp[pos][sum][p];
 60   int last = limit ? digit[pos] : 9;
 61 
 62   Node a;
 63   ans.cnt = 0, ans.sum = 0;
 64   for( int i = 0; i <= last; ++i ){
 65     if( i == 0 && flag ){
 66       a = dfs( pos-1, sum, p, flag, limit&&(i == last) );
 67     }else{
 68       if(p){
 69         a = dfs( pos-1, sum-i, p^1, 0, limit&&(i == last) );
 70       }else{
 71         a = dfs( pos-1, sum+i, p^1, 0, limit&&(i == last) );
 72       }
 73     }
 74     ans.cnt = (ans.cnt + a.cnt + mod)%mod;
 75     ans.sum = (ans.sum + (c[pos]*i%mod*a.cnt)%mod + a.sum + mod)%mod;
 76   }
 77 
 78   if(!limit && !flag){
 79     dp[pos][sum][p].cnt = ans.cnt;
 80     dp[pos][sum][p].sum = ans.sum;
 81   }
 82 
 83   return ans;
 84 }
 85 
 86 int bitSet( int64 num ){
 87   int len = 0;
 88   memset( digit, 0, sizeof(digit) );
 89 
 90   while(num){
 91     digit[len++] = num%10;
 92     num /= 10;
 93   }
 94 
 95   return len-1;
 96 }
 97 
 98 void InitDP(void){
 99   memset( dp, -1, sizeof(dp) );
100 }
101 
102 void solve(void){
103   InitDP();
104 
105   int len;
106   len = bitSet(l-1);
107   //cout << "len1: " << len << endl;
108   Node ans1 = dfs(len, k+100, 1, 1, 1);
109   //cout << ans1.sum << endl;
110   len = bitSet(r);
111   //cout << "len2: " << len << endl;
112   Node ans2 = dfs(len, k+100, 1, 1, 1);
113 
114   printf("%lld\n", ((ans2.sum - ans1.sum + mod)%mod));
115 }
116 
117 int main(void){
118   Init();
119   while(scanf("%lld%lld%d", &l, &r, &k) != EOF){
120     solve();
121   }
122 
123   return 0;
124 }
View Code

注意下dfs过程中sum不能小于0或超过200。

转载于:https://www.cnblogs.com/zhazhalovecoding/p/5435376.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值