数位\(dp\)搞了一上午才搞懂。靠这种傻\(X\)的东西竟然花了我一上午的时间。

数位\(dp\)

概念

数位\(dp\)就是强制你分类一些数,例如给你一段区间,然后让你求出不包含\(2\)的数的个数。

思想

利用前缀和的思想,然后求出区间端点的前缀和这样作差就可以了。

实现方式

有两种实现方式。

记忆化搜索版

这种方法比较好理解(例题不要\(37\))

int dfs(int pos,int pre,int sta,bool limit) {
if (pos==-1) return 1;
if (!limit && dp[pos][sta]!=-1) return dp[pos][sta];
int u = limit?a[pos]:9;
int cnt = 0;
for (int i=0; i<=u; ++i) {
if (i==4 || (pre==3&&i==7)) continue;
cnt += dfs(pos-1,i,i==3,limit&&i==a[pos]);
}
if (!limit) dp[pos][sta] = cnt;
return cnt;
}

查询区间\([0 \ldots n]\)

动态规划版

(例题不要\(62\))

void get_dp()
{
dp[0][0]=1;
for (int i=1;i<10;i++)
{
for (int j=0;j<10;j++)
{
if (j==4) dp[i][j]=0;
else if (j==6)
{
for (int k=0;k<10;k++)
dp[i][j]+=dp[i-1][k];
dp[i][j]-=dp[i-1][2];
}
else
{
for (int k=0;k<10;k++)
dp[i][j]+=dp[i-1][k];
}
}
}
}

查询区间\([0\ldots n)\)

完整代码

动态规划

#include<cstdio>

const int maxn=10;
long long dp[maxn][10]; void get_dp()
{
dp[0][0]=1;
for (int i=1;i<10;i++)
{
for (int j=0;j<10;j++)
{
if (j==4) dp[i][j]=0;
else if (j==6)
{
for (int k=0;k<10;k++)
dp[i][j]+=dp[i-1][k];
dp[i][j]-=dp[i-1][2];
}
else
{
for (int k=0;k<10;k++)
dp[i][j]+=dp[i-1][k];
}
}
}
} int a[maxn];
long long solve(int n)
{
a[0]=0;
while (n)
{
a[++a[0]]=n%10;
n/=10;
}
long long ans=0;
a[a[0]+1]=0;
for (int i=a[0];i>=1;i--)
{
for (int j=0;j<a[i];j++)
if(j!=4 && !(a[i+1]==6 && j==2))
ans+=dp[i][j];
if (a[i]==4) break;
if (a[i+1]==6 && a[i]==2) break;
}
return ans;
} int main()
{
int n,m;
get_dp();
while (scanf("%d %d",&n,&m)==2 && (n||m))
{
long long k1=solve(m+1);
long long k2=solve(n);
printf("%I64d\n",k1-k2);
}
return 0;
}

关于动态规划版有个难点,就是\(solve\)函数里面的两个\(break\)。因为我们枚举的是最高位,所以当我们最高位枚举到不合法数的时候,我们就会固定,那么剩下数的任何数都是不合法的,所以\(break\)

记忆化搜索

#include<cstdio>
#include<iostream>
#include<cstring> using namespace std;
typedef long long LL; int a[20],p;
int dp[20][2]; int dfs(int pos,int pre,bool sta,bool limit) {
if (pos==-1) return 1;
if (!limit && dp[pos][sta]!=-1) return dp[pos][sta];
int u = limit?a[pos]:9;
int cnt = 0;
for (int i=0; i<=u; ++i) {
if (i==4 || (pre==3&&i==7)) continue;
cnt += dfs(pos-1,i,i==3,limit&&i==a[pos]);
}
if (!limit) dp[pos][sta] = cnt;
return cnt;
} int work(int x) {
p = 0;
while (x) {
a[p++] = x%10;
x /= 10;
}
return dfs(p-1,-1,0,true);
} int main() {
memset(dp,-1,sizeof(dp));
int l,r;
cin>>l>>r;
printf("%d",work(r)-work(l-1));
return 0;
}

以上代码借鉴。

数位$dp$的更多相关文章

  1. BZOJ 1911: [Apio2010]特别行动队 [斜率优化DP]

    1911: [Apio2010]特别行动队 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 4142  Solved: 1964[Submit][Statu ...

  2. BZOJ 1597: [Usaco2008 Mar]土地购买 [斜率优化DP]

    1597: [Usaco2008 Mar]土地购买 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4026  Solved: 1473[Submit] ...

  3. Light OJ 1031---Easy Game(区间DP)

    题目链接 http://lightoj.com/volume_showproblem.php?problem=1031 Description You are playing a two player ...

  4. HDU 5807 Keep In Touch DP

    Keep In Touch Problem Description   There are n cities numbered with successive integers from 1 to n ...

  5. 17996 Daily Cool Run (dp)

    时间限制:1000MS  内存限制:65535K 提交次数:0 通过次数:0 题型: 编程题   语言: 不限定 Description Daily Cool Run is a popular gam ...

  6. hdu 1028 Ignatius and the Princess III 简单dp

    题目链接:hdu 1028 Ignatius and the Princess III 题意:对于给定的n,问有多少种组成方式 思路:dp[i][j],i表示要求的数,j表示组成i的最大值,最后答案是 ...

  7. BC.5200.Trees(dp)

    Trees  Accepts: 156  Submissions: 533  Time Limit: 2000/1000 MS (Java/Others)  Memory Limit: 65536/6 ...

  8. hdu 5115 区间dp ***

    题意:有n只狼,每只狼有两种属性,一种攻击力一种附加值,我们没杀一只狼,那么我们受到的伤害值为这只狼的攻击值与它旁边的两只狼的附加值的和,求把所有狼都杀光受到的最小的伤害值. 枚举中间k作为最后杀死的 ...

  9. HDU 4258 Covered Walkway 斜率优化DP

    Covered Walkway Problem Description   Your university wants to build a new walkway, and they want at ...

  10. HDU 3853(期望DP)

    题意: 在一个r*c的网格中行走,在每个点分别有概率向右.向下或停止不动.每一步需要的时间为2,问从左上角走到右下角的期望时间. SOL: 非常水一个DP...(先贴个代码挖个坑 code: /*== ...

随机推荐

  1. HDOJ 2189 悼念512汶川大地震遇难同胞——来生一起走 【母函数】

    题意:非常清楚不解释. 策略:如题. 就是个简单的母函数的改变. 这道题做了好久,才明确是那有毛病,还是理解的不够深刻. AC代码: #include<stdio.h> #include& ...

  2. video_capture模块分析

    1. 对外接口      VideoCaptureModule     控制接口      VideoCaptureDataCallback Vie中的ViECapturer继承,用于响应抓包数据 2 ...

  3. vijos-1382 寻找主人

    题意: 给出两个同样长度的数字串: 求两个串是否本质同样.同样则输出最小表示. 长度L似乎给的不正确,大概是2000000左右吧: 题解: 最小表示法裸题.证明正确性啥的详见论文吧: 这东西大体的思路 ...

  4. bzoj2768: [JLOI2010]冠军调查(双倍经验最小割)

    2768: [JLOI2010]冠军调查 题目:传送门 题解: 双倍经验(1934) 代码: #include<cstdio> #include<cstring> #inclu ...

  5. Java多线程编程模式实战指南(三):Two-phase Termination模式--转载

    本文由本人首次发布在infoq中文站上:http://www.infoq.com/cn/articles/java-multithreaded-programming-mode-two-phase-t ...

  6. WPF学习(四) - 附加属性

    冷静了一晚,我就当这次学习的过程是在看狗血剧情的武打小说吧:没有垃圾的武术,只有垃圾的武者…… 还有个话儿怎么说来着:你们是用户,不是客户,也就有个使用的权力.搞清楚身份,别叽叽歪歪的! 没办法,全世 ...

  7. WPF Template

    ControlTemplate ControlTemplate:用于定义控件的结构和外观,这样可以将控件外观与控件功能分离开. 在xaml中ControlTemplate通常配置到Style中,通过S ...

  8. pagination使用说明

    参考自张鑫旭 准备工作 下载jquery.min.js 下载jquery.pagination.js 下载pagination.css 开始敲代码 第一步,引入刚刚下载的三个文件 <link r ...

  9. 一、数组---数组中的K-diff数对※※※※※

    给定一个整数数组和一个整数 k, 你需要在数组里找到不同的 k-diff 数对.这里将 k-diff 数对定义为一个整数对 (i, j), 其中 i 和 j 都是数组中的数字,且两数之差的绝对值是 k ...

  10. 链表(list)--c实现

    做c的开发有1年多了,期间写过c++,感觉基础不够好,补上去,不丢人.o(^▽^)o to better myself. #include <stdio.h> #include <s ...