ZJOI2010数字计数-数位DP

时间:2019-06-13
本文章向大家介绍ZJOI2010数字计数-数位DP,主要包括ZJOI2010数字计数-数位DP使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

ZJOI2010数字计数

题目传送

sol:

仍然可以按照记忆化实现的思路来解决此题。

\(pos,lim,lead\)的含义不再申明,不了解可以看这里(含义是一样的),也可以阅读那里面的那篇链接博文。

此题中只需多记录一个变量\(cnt\),表示计算的数\(now\),在\(pos\)位中已经出现了\(cnt\)次。

其上的\(now\)从0~9枚举,相当于分别计算答案。

为什么要记一个\(cnt\)呢。

可以这样理解:当搜索到边界的时候需要返回的值,就是当前所有的位中,\(now\)出现的次数,也即\(cnt\)

#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define IL inline
#define LL long long
#define DB double
using namespace std;

int len,now,a[15];
LL ans[15],f[15][15];

LL dfs(int pos,int cnt,int lim,int lead) {
    if(pos>len) return cnt;
    if(!lim&&f[pos][cnt]!=-1) return f[pos][cnt];
    RG LL sum=0;
    RG int i,up=lim?a[len-pos+1]:9;
    for(i=0;i<=up;++i)
        if(lead&&i==0) sum+=dfs(pos+1,0,0,1);
        else sum+=dfs(pos+1,cnt+(i==now),lim&&i==up,0);
    
    if(!lim&&!lead) f[pos][cnt]=sum;
    return sum;
}

IL LL getans(LL x) {
    for(len=0;x;x/=10) a[++len]=x%10;
    memset(f,-1,sizeof(f));
    return dfs(1,0,1,1);
}

int main()
{
    RG LL l,r;
    scanf("%lld%lld",&l,&r);
    for(now=0;now<=9;++now)
        printf("%lld ",getans(r)-getans(l-1));
    return 0;
}

原文地址:https://www.cnblogs.com/Bhllx/p/11017792.html