51nod 1009 数字1的数量 (my 数位dp入门)

来源:互联网 发布:淘宝隐藏导航栏代码 编辑:程序博客网 时间:2024/06/05 00:27

给定一个十进制正整数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;}



原创粉丝点击