不要62 HDU - 2089 && Bomb HDU - 3555 (入门数位dp)

本文深入探讨了数位DP算法的应用,通过实例讲解了如何利用数位DP解决车牌号筛选和炸弹计数问题,详细解释了状态转移方程和状态压缩技巧,帮助读者掌握数位DP的核心思想。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

Input

输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。 

Output

对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。 

Sample Input

1 100
0 0

Sample Output

80

 题解:可以打表,但是做这道题的目的就是为了学数位dp的思想

dp 就是状态,状态要唯一,状态一样的合并。 状态转移方程。数位dp 顾名思义dp数组中是为了记数的。

本题中 我开的是三维数组 dp[pos][stat][limit]   第一维表示当前在pos位,stat表状态(不同题目他的状态也不同),本题而言就两种状态,前面哪一位是不是6,是6为一种状态(当前位不能为2),不是6是一种状态,为了计数;limit 看看前面位有没有限制,如输入1234567,当前4位为 1234 那么此时,第五位就有限制了,第五位最大不能超过5,这是有限制的情况,当前四位了 1134 那么第五位就没有限制,可以是0~9之间的任意一个数,当前状况,不管第五位取0 还是 9,第六、七位,都是取0~9的任意一个数,所有当前这一位没有限制的话,后面那几位,能取得到数的总数是确定的,在不考虑其他情况的条件下,没有限制可以看做为一种状态。 

数位dp详解:点击链接

方法一 代码:

#include<bits/stdc++.h>
using namespace std;
#define Max 10010

int a[10];
int dp[20][2][2]; // dp[pos][stat][limit] 不考虑其他情况,没有限制的可以看做一种状态 
  // stat 表示状态,就这道题而言,就两个状态前面哪一位是不是 6,如果是6的话,那么当前位就不能取2,存除当前位
  //为2的所有情况。 
// 为什么说没有限制的可以看做一种状态,如输入1234567,当前4位为 1234 那么此时,第五位就有限制了,第五位最大不能超过5,这是有限制的情况
// 当 前四位了 1134 那么第五位就没有限制,可以是0~9之间的任意一个数,当前状况,不管第五位取0 还是 9,第六、七位,都是取
// 0~9的任意一个数,所有当前这一位没有限制的话,后面那几位,能取得到数的总数是确定的,
// 在不考虑其他情况的条件下,可以看做一种状态。

int dfs(int pos,int stat,int limit)
{
	if(pos==-1)
		return 1;
	if(dp[pos][stat][limit]!=-1) 
		return dp[pos][stat][limit];
	int tt = limit?a[pos]:9;
	int sum = 0;
	for(int i = 0;i<=tt;i++)
	{
		if(stat&&i==2) continue;
		if(i==4) continue;
		sum += dfs(pos-1,i==6,limit&&i==a[pos]);
	}
	return dp[pos][stat][limit] = sum;
}
int solve(int x)
{
	int sum = 0;
	while(x)
	{
		a[sum++] = x%10;
		x /= 10;
	}
	memset(dp,-1,sizeof(dp));
	return dfs(sum-1,0,1);
} 
int main()
{
	int n,m;
	while(~scanf("%d%d",&n,&m)&&(n+m))
	{
		printf("%d\n",solve(m) - solve(n-1));
	}
	return 0;
}

方法二:memset 函数优化,放在多组数据的外面。

代码:

#include<bits/stdc++.h>
using namespace std;
#define Max 10010

int a[30];
int dp[30][2]; // dp[pos][stat][limit] 不考虑其他情况,没有限制的可以看做一种状态 
  // stat 表示状态,就这道题而言,就两个状态前面哪一位是不是 6,如果是6的话,那么当前位就不能取2,存除当前位
  //为2的所有情况。 
// 为什么说没有限制的可以看做一种状态,如输入1234567,当前4位为 1234 那么此时,第五位就有限制了,第五位最大不能超过5,这是有限制的情况
// 当 前四位了 1134 那么第五位就没有限制,可以是0~9之间的任意一个数,当前状况,不管第五位取0 还是 9,第六、七位,都是取
// 0~9的任意一个数,所有当前这一位没有限制的话,后面那几位,能取得到数的总数是确定的,
// 在不考虑其他情况的条件下,可以看做一种状态。

int dfs(int pos,int stat,int limit)  
{
	if(pos==-1)
		return 1;
	if(!limit&&dp[pos][stat]!=-1)   // 可以减少记录的状态,当没有限制时才存。 
		return dp[pos][stat];
	int tt = limit?a[pos]:9;
	int sum = 0;
	for(int i = 0;i<=tt;i++)
	{
		if(stat&&i==2) continue;
		if(i==4) continue;
		sum += dfs(pos-1,i==6,limit&&i==a[pos]);
	}
	if(!limit) dp[pos][stat] = sum;
	return sum;
}
int solve(int x)
{
	int sum = 0;
	while(x)
	{
		a[sum++] = x%10;
		x /= 10;
	}
	return dfs(sum-1,0,1);
} 
int main()
{
	int n,m;
	memset(dp,-1,sizeof(dp));    // 为什么减少dp中limit的状态,就是为了memset优化,放到多组数据的外面。  
	while(~scanf("%d%d",&n,&m)&&(n+m))
	{
		printf("%d\n",solve(m) - solve(n-1));
	}
	return 0;
}

 

Bomb  HDU - 3555 

The counter-terrorists found a time bomb in the dust. But this time the terrorists improve on the time bomb. The number sequence of the time bomb counts from 1 to N. If the current number sequence includes the sub-sequence "49", the power of the blast would add one point. 
Now the counter-terrorist knows the number N. They want to know the final points of the power. Can you help them? 

Input

The first line of input consists of an integer T (1 <= T <= 10000), indicating the number of test cases. For each test case, there will be an integer N (1 <= N <= 2^63-1) as the description. 

The input terminates by end of file marker. 

Output

For each test case, output an integer indicating the final points of the power.

Sample Input

3
1
50
500

Sample Output

0
1
15


        
  

Hint

From 1 to 500, the numbers that include the sub-sequence "49" are "49","149","249","349","449","490","491","492","493","494","495","496","497","498","499",
so the answer is 15.

题意:输入t,包含t组数据,每组数据一个n,求0~n中有多少个包含49的数

思路:数位dp

代码:

#include<bits/stdc++.h>
using namespace std;
#define Max 40
#define ll long long
ll dp[Max][2][2];  //dp[pos][ok][stat]  当前为pos为,ok 为是否这个已经是包含了49,
 //stat为pos前面是不是等于4,dp[pos][ok][stat]存当前位于pos位且前一位的状态为stat,前面所有位否包含49的状态下
 //会存在多少包含49的数。   
ll a[Max];


ll dfs(ll pos ,bool ok,ll stat,ll limit)
{
	
	if(pos==-1)
		return ok;
	//printf("pos==%lld stat==%lld tt==%lld\n",pos,stat,tt);
	if(!limit&&dp[pos][ok][stat]!=-1)
		return dp[pos][ok][stat];
	
	ll tt = limit?a[pos]:9;
	ll sum = 0;
	for(ll i = 0; i <= tt; i ++)
	{
		bool flag = false;
		if(ok) flag = true;
		if(stat==1&&i==9)
		{
			flag = true;
		} 
		sum += dfs(pos-1,flag,i==4,limit && i==a[pos]);
	}
	if(!limit) dp[pos][ok][stat] = sum;
	return sum;
}
ll solve(ll n)
{
	ll sum = 0;
	
	while(n)
	{
		a[sum++] = n%10;
		n /= 10;
	} 
	return dfs(sum-1,false,0,1);
}
int main()
{
	int t;
	memset(dp,-1,sizeof(dp));  // memset 函数 优化 
	scanf("%d",&t);
	while(t--)
	{
		ll n;
		scanf("%lld",&n);
		printf("%lld\n",solve(n));
	}
	return 0;
} 

 

### HDU OJ 2089 Problem Solution and Description The problem titled "不高兴的津津" (Unhappy Jinjin) involves simulating a scenario where one needs to calculate the number of days an individual named Jinjin feels unhappy based on certain conditions related to her daily activities. #### Problem Statement Given a series of integers representing different aspects of Jinjin's day, such as homework completion status, weather condition, etc., determine how many days she was not happy during a given period. Each integer corresponds to whether specific events occurred which could affect her mood positively or negatively[^1]. #### Input Format Input consists of multiple sets; each set starts with two positive integers n and m separated by spaces, indicating the total number of days considered and types of influencing factors respectively. Following lines contain details about these influences over those days until all cases are processed when both numbers become zero simultaneously. #### Output Requirement For every dataset provided, output should be formatted according to sample outputs shown below: ```plaintext Case k: The maximum times of appearance is x, the color is c. ``` Where `k` represents case index starting from 1, while `x` stands for frequency count and `c` denotes associated attribute like colors mentioned earlier but adapted accordingly here depending upon context i.e., reasons causing unhappiness instead[^2]. #### Sample Code Implementation Below demonstrates a simple approach using Python language to solve this particular challenge efficiently without unnecessary complexity: ```python def main(): import sys input = sys.stdin.read().strip() datasets = input.split('\n\n') results = [] for idx, ds in enumerate(datasets[:-1], start=1): data = list(map(int, ds.strip().split())) n, m = data[:2] if n == 0 and m == 0: break counts = {} for _ in range(m): factor_counts = dict(zip(data[2::2], data[3::2])) for key, value in factor_counts.items(): try: counts[key] += value except KeyError: counts[key] = value max_key = max(counts, key=lambda k:counts[k]) result_line = f'Case {idx}: The maximum times of appearance is {counts[max_key]}, the reason is {max_key}.' results.append(result_line) print("\n".join(results)) if __name__ == '__main__': main() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值