算法学习之路|数位dp简要分析

简介: 数位dp简要分析

数位dp一般用于处理一些和数位有关的计数问题,比如说求区间[l,r]中有多少符合条件的数,而为了减少时间复杂度,方法使用的是动态规划的思想。

举例说明:问从0到2345这些数中总共包含多少6。

数位dp的思路是:

1.由于千位是2,首先求出[0,2000)中满足条件的个数,因为此时个十百位可以任意取值,不受上界的限制。

2.之后由于千位已经到达最高,要改为考虑百位,此时百位受到上界的限制,所以之后需要求出[2000,2300)中马满足条件的个数,此时十位和个位不受限制。

3.当百位是3时,十位又受到限制…以此类推。

当然,如何计算一个整百整千的区间的满足条件的个数,也需要在代码中体现,比如这里f(2000)=2f(1000)=2(100+10f(100))=2(100+10(10+10f(10)))

以下是数位dp的模板:

 


#include<stdio.h>
#include<algorithm>
#include<iostream>
#define n 20
using namespace std;
typedef long long ll;
ll dp[n][state];//state作为状态,不同的题目可能有不同的状态个数,有时甚至需要改变dp的维数,第一维代表数的长度
ll dd[n];//将数的每一位存储到数组
ll dfs(int pos,int state,bool lead,bool limit)
/*pos表示当前的数位,此处pos=0表示个位,pos=1表示十位,以此类推
state表示状态参数,也可以有多个状态参数
lead表示前导零(一般来说只有当答案和0有关系时才需要这个参数)
limit表示当前pos位是否受限)*/
{
    if(pos==-1)//表示已经搜索结束
        return 1;//返回并不确定,结合实际情况改变
    if(!lead&&!limit&&dp[pos][state]!=-1)//在不受限的情况下如果dp已被更新,则直接返回
        return dp[pos][state];
    int now=limit?dd[pos]:9;//now用以确定搜索终点,不受限就是9,受限就是当前pos位的数值
    ll ans=0;
    for(int i=0;i<=now;i++)//注意边界
    {
        ans+=dfs(pos-1,newstate,newlead,limit&&i==now);//只有前面所有位数都受限,下一位才受限
    }
    if(!limit&&!lead)//只有当不受限时(即范围为整十,整百...),才更新dp数组,因为受限区间不能代表整区间
        dp[pos][state]=ans;
    return ans;
}

例题:

hdu2089


所有含有4或者含有62的数都是不吉利的,求一定范围内有多少吉利的数。

ac代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
ll dp[7][10];
ll dd[7];
ll dfs(int pos,int pre,bool limit)//这里前导零不影响结果,不需要lead   pre表示pos位前一位的数字
{
    if(pos==-1)
        return 1;//进行到这里说明之前位已经全部通过,返回1
    if(!limit&&dp[pos][pre]!=-1)
        return dp[pos][pre];
    int now=limit?dd[pos]:9;
    ll ans=0;
    for(int i=0;i<=now;i++)
    {
        if(i==4||i==2&&pre==6)continue;//是不吉利的数就跳过
        ans+=dfs(pos-1,i,limit&&(i==dd[pos]));
    }
     if(!limit)
        dp[pos][pre]=ans;
    return ans;
}
ll build(int n)//计算从1-n的个数
{
    int k=0;
    while(n)
    {
        dd[k++]=n%10;
        n/=10;
    }
    return dfs(k-1,0,true);
}
int main()
{
    memset(dp,-1,sizeof(dp));//初始化
    int a,b;
    while(scanf("%d%d",&a,&b),a+b)
    {
        printf("%ld\n",build(b)-build(a-1));
    }
    return 0;
}
目录
相关文章
|
1月前
|
机器学习/深度学习 人工智能 监控
AI算法分析,智慧城管AI智能识别系统源码
AI视频分析技术应用于智慧城管系统,通过监控摄像头实时识别违法行为,如违规摆摊、垃圾、违章停车等,实现非现场执法和预警。算法平台检测街面秩序(出店、游商、机动车、占道)和市容环境(垃圾、晾晒、垃圾桶、路面不洁、漂浮物、乱堆物料),助力及时处理问题,提升城市管理效率。
AI算法分析,智慧城管AI智能识别系统源码
|
1月前
|
算法
经典控制算法——PID算法原理分析及优化
这篇文章介绍了PID控制算法,这是一种广泛应用的控制策略,具有简单、鲁棒性强的特点。PID通过比例、积分和微分三个部分调整控制量,以减少系统误差。文章提到了在大学智能汽车竞赛中的应用,并详细解释了PID的基本原理和数学表达式。接着,讨论了数字PID的实现,包括位置式、增量式和步进式,以及它们各自的优缺点。最后,文章介绍了PID的优化方法,如积分饱和处理和微分项优化,以及串级PID在电机控制中的应用。整个内容旨在帮助读者理解PID控制的原理和实际运用。
87 1
|
6天前
|
机器学习/深度学习 算法 前端开发
Scikit-learn进阶:探索集成学习算法
【4月更文挑战第17天】本文介绍了Scikit-learn中的集成学习算法,包括Bagging(如RandomForest)、Boosting(AdaBoost、GradientBoosting)和Stacking。通过结合多个学习器,集成学习能提高模型性能,减少偏差和方差。文中展示了如何使用Scikit-learn实现这些算法,并提供示例代码,帮助读者理解和应用集成学习提升模型预测准确性。
|
6天前
|
算法 数据可视化 Python
Python中LARS和Lasso回归之最小角算法Lars分析波士顿住房数据实例
Python中LARS和Lasso回归之最小角算法Lars分析波士顿住房数据实例
11 0
|
7天前
|
机器学习/深度学习 算法 Python
使用Python实现集成学习算法:Bagging与Boosting
使用Python实现集成学习算法:Bagging与Boosting
17 0
|
7天前
|
算法 定位技术 Windows
R语言最大流最小割定理和最短路径算法分析交通网络流量拥堵问题
R语言最大流最小割定理和最短路径算法分析交通网络流量拥堵问题
13 4
|
11天前
|
算法
算法系列--两个数组的dp问题(2)(下)
算法系列--两个数组的dp问题(2)(下)
17 0
|
11天前
|
算法 计算机视觉
算法系列--两个数组的dp问题(1)(下)
算法系列--两个数组的dp问题(1)
18 0
|
11天前
|
算法
算法系列--两个数组的dp问题(1)(上)
算法系列--两个数组的dp问题(1)
14 0
|
14天前
|
算法
【算法学习--字符串】(不含KMP算法)
【算法学习--字符串】(不含KMP算法)

热门文章

最新文章