【数位dp入门】51nod 1009 数字1的数量

给定一个十进制正整数N,写下从1开始,到N的所有正数,计算出其中出现所有1的个数。

N(1 <= N <= 10^9)


dp[i] 表示 0 ~ (10 ^ i - 1) 中1的个数。

ten[i] 表示 10 ^ i 的值

pos 当前处理的位

num 当前处理的位前面已经有的1个数

limit 当前位有没限制

其实dp可以看作记录过程答案的dfs。(即是记忆化搜索) 可以把这题当作dfs做。

对于 0 ~ 4321 有多少个1呢?

图:

修正:虽然这题过掉了,后来做 hdu 2098 ,根据我自己的理解码代码,无限wa,不知道是错在哪里,后来强行手跑代码,发现先前的理解不准确。

进一步理解:数位dp的记忆化搜索不能理解为边爆搜边记录,这样是没有意义的(之前脑子懵),如上图:它先在最深一层搜10次(0000~0009),记录dp值,运用在最后第二层搜10次(001X~009X)上,以此类推,搞出所有需要的dp值无非只搜了 (位数*10)次;


#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<map>
#include<queue>
#include<cmath>
#include<algorithm>
#include<deque>
typedef long long LL;
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
const int INF=0x3f3f3f3f;
const int N = 20;
const double eps = 1e-6;


int ten[N]; //10^i 的值
void init()
{
    ten[0] = 1;
    for(int i = 1; i < 10; i++)
        ten[i] = ten[i-1]*10;
}

char s[N];
int len;
int dp[N]; //0->10^i-1   中1的个数
int dfs(int pos,int num, int limit)
{
    if(pos == len)
        return num;
    if(!limit && dp[len-pos-1] != -1)
        return num*ten[len-pos]+dp[len-pos-1];
    int up = limit ? s[pos]-'0' : 9;
    int tmp = 0;
    for(int i = 0; i <= up; i++)
        tmp += dfs(pos+1,num+(i==1),limit && s[pos]-'0' == i);
    if(!limit)
        dp[len-pos-1] = tmp;
    return tmp;
}

int main()
{
    init();
    scanf("%s",s);
    len = strlen(s);
    memset(dp,-1,sizeof(dp));
    printf("%d\n",dfs(0,0,1));
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值