HDU 2089 不要62(数位DP,三种姿势)

HDU 2089 不要62(数位DP,三种姿势)

ACM

题目地址:HDU 2089

题意:

中文题意,不解释。

分析:

  1. 100w的数据,暴力打表能过
  2. 先初始化dp数组,表示前i位的三种情况,再进行推算
  3. 直接dfs,一遍搜一变记录,可能有不饥渴的全部算和饥渴的部分算情况,记录只能记录全部算(推荐看∑大的详细题解Orz)

代码:

1. 暴力 (以前写的)

/*
*  Author:      illuz <iilluzen[at]gmail.com>
*  File:        2089_bf.cpp
*  Create Date: 2014-03-31 20:28:46
*  Descripton:  brute force way
*/

#include <cstdio>
#define RII(x,y) scanf("%d%d",&x,&y)
#define PIN(x) printf("%d\n",x)
#define repf(i,a,b) for(int i=(a);i<=(b);i++)

const int N = 1000010;

int f[N], n, m;

bool check(int r) {
	while (r) {
		if (r % 10 == 4) return false;
		if (r % 100 == 62) return false;
		r /= 10;
	}
	return true;
}

void init() {
	repf (i, 1, 1000000)
		if (check(i))
			f[i] = f[i - 1] + 1;
		else
			f[i] = f[i - 1];
}

int main()
{
	init();
	while (RII(n, m) && (n || m)) {
		PIN(f[m] - f[n - 1]);
	}
	return 0;
}

2. DP_1

/*
*  Author:      illuz <iilluzen[at]gmail.com>
*  File:        2089.cpp
*  Create Date: 2014-07-26 09:55:48
*  Descripton:
*/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define RII(x,y) scanf("%d%d",&x,&y)
#define PIN(x) printf("%d\n",x)
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
#define repd(i,a,b) for(int i=(a);i>=(b);i--)

const int N = 10;

int n, m;
int bits[N];
int dp[N][3];	// [len][x]
				// 0->luck
				// 1->luck and highest is 2
				// 2->unluck

void init() {
	dp[0][0] = 1;	// len is 0 and luck is 1, becauses the dp[1][1] will equal it.
	dp[0][1] = dp[0][1] = 0;

	repf(i, 1, N - 1) {

		dp[i][0] = dp[i - 1][0] * 9		// i-1_luck without 4
					- dp[i - 1][1];		// and without 62

		dp[i][1] = dp[i - 1][0];		// equal to i-1_luck_2 + '6'

		dp[i][2] = dp[i - 1][2] * 10	// unluck is always unluck
			+ dp[i - 1][0]				// i-1_luck + '4'
			+ dp[i - 1][1];				// i-1_luck_2 + '6'

	}
}

int solve(int num) {
	int len = 0, rec = num, ans, flag;

	// get bits array
	while (num) {
		bits[++len] = num % 10;
		num /= 10;
	}
	bits[len + 1] = 0;

	ans = 0;	// the unluck num
	flag = 0;	// if appear unluck
	repd (i, len, 1) {
		ans += dp[i - 1][2] * bits[i];	// unluck is always unluck

		if (flag) {						// if unluck appeared
			ans += dp[i - 1][0] * bits[i];	// all luck become unluck
		} else {
			if (bits[i] > 4) {
				ans += dp[i - 1][0];	// i-1_luck + '4'
			}
			if (bits[i] > 6) {
				ans += dp[i - 1][1];	// i-1_luck_2 + '6'
			}
			if (bits[i + 1] == 6 && bits[i] > 2) {
				ans += dp[i][1];
			}
		}

		if (bits[i] == 4 || (bits[i + 1] == 6 && bits[i] == 2)) {
			flag = 1;
		}
	}

	return rec - ans;
}

int main() {
	init();
	while (~RII(n, m) && (n || m)) {
		PIN(solve(m + 1) - solve(n));
	}
	return 0;
}

3. DP_2(DFS)

/*
*  Author:      illuz <iilluzen[at]gmail.com>
*  File:        2089_dfs.cpp
*  Create Date: 2014-07-26 15:21:12
*  Descripton:  dfs version
*/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define RII(x,y) scanf("%d%d",&x,&y)
#define PIN(x) printf("%d\n",x)

const int N = 10;

int bits[N], dp[N][2];	// dp[i][is6] is the number of i-len digits with (if prevent number is 6), its digits are from 0-9

// the rest length, Is the prevent digit 6, Is the digit max
int dfs(int len, bool is6, bool ismax) {
	if (len == 0)
		return 1;
	if (!ismax && dp[len][is6] >= 0)		// dp
		return dp[len][is6];

	int cnt = 0, mmax = (ismax? bits[len] : 9);
	for (int i = 0; i <= mmax; i++) {
		if (i == 4 || is6 && i == 2)	// unluck digit
			continue;
		cnt += dfs(len - 1, i == 6, ismax && i == mmax);
	}

	return ismax ? cnt : dp[len][is6] = cnt;	// remember the result
}

int solve(int num) {
	int len = 0;
	while (num) {
		bits[++len] = num % 10;
		num /= 10;
	}

	return dfs(len, false, true);
}

int main() {
	int n, m;
	memset(dp, -1, sizeof(dp));
	while (~scanf("%d%d", &n, &m) && (n || m)) {
		PIN(solve(m) - solve(n - 1));
	}
	return 0;
}

HDU 2089 不要62(数位DP,三种姿势),布布扣,bubuko.com

时间: 2024-12-26 05:04:36

HDU 2089 不要62(数位DP,三种姿势)的相关文章

[ACM] hdu 2089 不要62(数位Dp)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 19043    Accepted Submission(s): 6442 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就

HDU 2089 不要62(数位dp)

题意:给定一个区间[n, m],求这个区间当中不含62和4的个数.例如62315,88914就是不符合条件的. 数位dp第一题,dp[i][j]表示以 j 开头的 i 位数满足条件的个数,先要预处理出来所有的情况, 下面是预处理的核心.其中k表示j后面的那一位.max_len是题目中给的n的最大位数,这里是7,第二层for是枚举第max_len - i位的值. for (int i = 1; i <= max_len; i++) { for (int j = 0; j <= 9; j++) {

HDU 2089 不要62(数位dp&amp;记忆化搜索)

题目链接:[kuangbin带你飞]专题十五 数位DP C - 不要62 题意 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众. 不吉利的数字为所有含有4或62的号码.例如: 62315 73418 88914 都属于不吉利号码.但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列. 你的任务是,对于每次给

HDU 2089 不要62 (数位dp水题)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 32358    Accepted Submission(s): 11514 题目链接 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样

HDU 2089 不要62 数位DP入门

Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众.不吉利的数字为所有含有4或62的号码.例如:62315 73418 88914都属于不吉利号码.但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列.你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多

HDU 2089 不要62 数位dp(入门

题目链接:点击打开链接 中文题. 问区间内有多少个合法数字(一个数是合法数字须满足1.不含4 ,2.每个6后面都不是2 dp[i][0]表示长度为i的数字中,前一位不为6时的合法个数, dp[i][1]表示长度为i的数字中前一位是6的合法个数. #include <cstdio> #include <algorithm> #include <cstring> #include <iostream> using namespace std; typedef l

HDU 2089 不要62 (数位DP)

Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众.不吉利的数字为所有含有4或62的号码.例如:62315 73418 88914都属于不吉利号码.但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列.你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多

hud 2089 不要62 (数位dp)

#include<stdio.h> #include<string.h> #include<math.h> #define max 10 int dp[max][3]; int number[max]; //dp[i][0] 前i位数中不符合要求的总个数 //dp[i][1] 前i位数中最高位是2的个数 //dp[i][2] 前i位数中存在含4和有连续62的个数 void init() { memset(dp,0,sizeof(dp)); dp[0][0]=1; for

HDU 3555 Bomb ,HDU 2089 深刻学习数位dp (各种方法乱用)

数位dp是与数位有关的区间统计 参考: 点击打开链接 思想是将数字拆分,dp[i][j] 长度为i的数字有多少个满足j条件的,从000~999 统计时,计当前数字为x,则其后面数字的变化的倍数是0~x-1 后面接000~999这样刚好统计不到这个数字n本身. eg: 对于一个数,若其首位已经比询问上界小,则剩余位没有任何限制.此时如果能直接处理这一情况,则问题距离解决又会迈出一大步. 例如,在十进制下,计算[10000,54321]内的数字和,我们可以将其分解为: [10000,19999],[