hdu 3555 Bomb(数位dp)

Posted jpphy0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 3555 Bomb(数位dp)相关的知识,希望对你有一定的参考价值。

问题

hdu 3555 Bomb - https://acm.hdu.edu.cn/showproblem.php?pid=3555

分析

状态转移

从低位到高位

  • 注意:图中的最高位是指当前已构造部分的最高位,并非指最终的最高位
!9
!9
!9 且 !4
4
任意
9
9
9
最高位不是9,也不含49
最高位为9,但不含49
含49

从高位到低位

  • 注意:图中的最低位是指当前已构造部分的最低位,并非指最终的最低位
!4
!4
!9 且 !4
9
任意
4
4
4
最低位不是4,也不含49
最低位为4,但不含49
含49

“高 ⇒ \\Rightarrow 低”枚举

  • 例如:求 5495 高 位 ← 低 位 \\overset{高位 \\leftarrow 低位}{5495} 5495以内的不含49的数字个数(包含:0000)
    • 最高高位取0时,则可取0999 - 0000内所有不含49的数
    • 最高高位取1时,则可取1999 - 1000内所有不含49的数
    • 最高高位取2时,则可取2999 - 2000内所有不含49的数
    • 最高高位取3时,则可取3999 - 3000内所有不含49的数
    • 最高高位取4时,则可取4999 - 4000内所有不是9开头的不含49的数
    • 最高高位取5时,则可取5495 - 5000内所有不含49的数
  • 如何求0999 - 0000、1999 - 1000、2999 - 2000、3999 - 3000、4999 - 4000、5495 - 5000内满足要求的数呢?
    • 0999 - 0000、1999 - 1000、2999 - 2000、3999 - 3000:所有999 - 000内的不含49的数
    • 4999 - 4000:所有999 - 000内的不是9开头的不含49的数(注意:90应看作090,不能看作以9开头)
    • 5495 - 5000:所有495 - 000内的不含49的数
    • 495 - 000是一个受限的3位数,而999 - 000 是一个不受限的3位数

dfs设计

  • 四类子问题
    • 不受限的m位不含49的数字个数【包含了9开头的不含49的数字】
    • 不受限的m位不是9开头的不含49的数字个数
    • 受限的m位不含49的数字个数【包含了9开头的不含49的数字】
    • 受限的m位不是9开头的不含49的数字个数(例如:495 - 000)
  • 参数
    • 数字位数, m m m
    • 是否受限, i s m a x ismax ismax
    • 是否包含9开头的不含49的数字, i s 4 is4 is4
  • 功能
    • 返回相应条件下的数字个数
    • 1、2两类子问题与状态表关系紧密,可以查表,也可以对表赋值

状态设计

  • 采用从低位到高位转移的方式
  • d p [ n ] [ s t a t e ] dp[n][state] dp[n][state]:长度n位的数字在state条件下 含49的数字个数
    • state = 0,表示所有不含49的数字个数,对应了dfs的第1类子问题
    • state = 1,表示最高位不是9的不含49的数字个数,对应了dfs的第2类子问题
  • dp数组 初始化 一次,也就是说状态表被多个测试样例 共享

代码

/* hdu 3555 Bomb 数位dp*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MXN = 25;
int n, b[MXN];
ll dp[MXN][2];
ll dfs(int m, int is4, bool ismax){
	if(m == 0) return 1;
	if(!ismax && ~dp[m][is4]) return dp[m][is4];
	ll ans = 0, end = ismax?b[m]:9;
	for(int i = 0; i <= end; ++i){
		if(is4 && i == 9) continue;
		ans += dfs(m-1, i == 4, ismax && i == end);
	}
	if(!ismax) dp[m][is4] = ans;
	return ans;
}
int main(){
	int t;
	ll N;
	scanf("%d", &t);
	以上是关于hdu 3555 Bomb(数位dp)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 3555Bomb 数位DP

Bomb HDU - 3555 (数位DP)

HDU - 3555 - Bomb(数位DP)

HDU 3555 Bomb (数位DP)

HDU 3555 Bomb (数位dp)

[HDU3555] Bomb 数位DP