在n到m中 有多少个1

这是数位的dp的基础题型,通过解析这道题可以了解到数位dp的基本板子,以前学长还讲过这个,现在拿到一道数位dp的题基本不会。。。希望以后可以改变这种情况。。。

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <math.h>
#include <string.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 20
#define mid 1e-8
#define LL long long
/********************************************************/
LL dp[N][N][N], d[N];
LL dfs(int now, int w, int tot, int fp)///now为当前的数字是第几位,w为当前的数字,tot为目前出现1的次数,fp为当前位是否达到上限值
{
    if(now==1) return tot;///搜索结束
    if(!fp&&dp[now][w][tot]!=-1) return dp[now][w][tot];///达到上限值返回

    int ma=(fp?d[now-1]:9);///设置上限
    LL ans=0;

    for(int i=0;i<=ma;i++)
        ans+=dfs(now-1, i, tot+(i==1?1:0), fp&&i==ma);///搜索下一位

    if(!fp&&dp[now][w][tot]==-1) dp[now][w][tot]=ans;///达到上限存储当前值
    return ans;
}

LL solve(LL x)
{
    if(x==0) return 0;
    LL X=x, sum=0;
    int len=0;
    while(X)///读取x的位数
    {
        d[++len]=X%10;///存储每一位作为上限
        X/=10;
    }

    for(int i=0;i<=d[len];i++)
        sum+=dfs(len, i, (i==1?1:0), i==d[len]);///暴力求解

    return sum;
}

int main()
{
    LL m, n;
    while(scanf("%lld%lld", &n, &m)!=EOF)
    {
        memset(dp, -1, sizeof(dp));
        printf("%lld\n", solve(m)-solve(n-1));
    }
    return 0;
}

 

posted on 2018-01-29 21:57  小春天  阅读(157)  评论(0编辑  收藏  举报

导航