HDU 2089 不要62

本文深入探讨数位动态规划(数位DP)的核心概念,通过实例解析如何设计DP数组,实现记忆化搜索以提高效率。特别关注状态设计与limit模式的理解,提供了一个数位DP的模板代码,帮助读者掌握解决区间统计问题的方法。

传送门

数位dp。
给一个左闭右闭区间,统计个数。

dp[i][j]表示当前从第i位枚举到最低位(第0位)、在j状态下符合条件的个数。
j表示第i+1位是不是6

初识数位dp,说几点看法。

  1. 之所以要设计这么个dp数组,就是为了重复利用(记忆化搜索)。不这么干的话,每种i,j的组合都可能要被计算多次。现在只用第一次计算,然后再碰见这样的i,j组合就不用再算了。
    当然,前提是不在limit模式下。
  2. 怎么设计这个dp?
    一般来说第一维都是表示pos,其他维度表示状态。这个状态一般是指最高位到第i+1位形成的一种前置状态,用来限制后续数位的生成。
    当不在limit模式下,要保证对于每一个可能的i,j组合,dp[i][j]的值都已经被定死了。
  3. limit模式的意思?
    solve(x)回答的的是[0,x]这个区间内的个数,limit用来限制这个数位的生成过程:不能超过x
    可以想到,随着dfs从高位到低位,有一条调用链正好生成了x,并且其中每一步都是limit模式。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <queue>
using namespace std;     // 数位dp模板

int n, m;
int dp[6][2];            // 无限制下,当前从第i位枚举到最低位(第0位)、符合条件的个数,j表示第i+1位是不是6。【可重复利用】
string num;

int dfs(int pos, int status, bool limit)
{
	if (pos == -1) return 1;
	if ((!limit) && (dp[pos][status] != -1)) return dp[pos][status]; // 记忆化搜索,重复利用

	int cnt = 0;
	int up = (limit ? (num[pos] - '0') : 9);                         // 这里num[]是字符
	for (int i = 0; i <= up; i++)
	{
		if (i == 4) continue;
		if ((status == 1) && (i == 2)) continue;
		cnt += dfs(pos - 1, i == 6 ? 1 : 0, limit && (i == up));     // 第三个参数都这么写
	}
	if (!limit) dp[pos][status] = cnt;
	return cnt;
}

int solve(int x)                         // 统计的是 0~x 符合条件的个数
{
	num = to_string(x);
	reverse(num.begin(), num.end());
	return dfs(num.size() - 1, 0, true);
}

int main()
{
	memset(dp, -1, sizeof dp);           // "约束条件是每个数自身的属性,而与输入无关" https://blog.youkuaiyun.com/wust_zzwh/article/details/52100392  
	for (; ~scanf("%d%d", &n, &m);)
	{
		if (n == 0 && m == 0) break;
		printf("%d\n", solve(m) - solve(n - 1));
	}

	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() ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值