您的位置:首页 > 其它

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

2017-05-15 22:57 411 查看
给定一个十进制正整数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
; //10^i 的值
void init()
{
ten[0] = 1;
for(int i = 1; i < 10; i++)
ten[i] = ten[i-1]*10;
}

char s
;
int len;
int dp
; //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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: