• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
The Great Julya Calendar 记忆化搜索-数位dp

The Great Julya Calendar 记忆化搜索-数位dp

题目

C1. The Great Julya Calendar

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Yet another Armageddon is coming! This time the culprit is the Julya tribe calendar.

The beavers in this tribe knew math very well. Smart Beaver, an archaeologist, got a sacred plate with a magic integer on it. The translation from Old Beaverish is as follows:

"May the Great Beaver bless you! May your chacres open and may your third eye never turn blind from beholding the Truth! Take the magic number, subtract a digit from it (the digit must occur in the number) and get a new magic number. Repeat this operation until a magic number equals zero. The Earth will stand on Three Beavers for the time, equal to the number of subtractions you perform!"

Distinct subtraction sequences can obviously get you different number of operations. But the Smart Beaver is ready to face the worst and is asking you to count the minimum number of operations he needs to reduce the magic number to zero.

Input

The single line contains the magic integer n, 0 ≤ n.

  • to get 20 points, you need to solve the problem with constraints: n ≤ \(10^6\) (subproblem C1);
  • to get 40 points, you need to solve the problem with constraints: n ≤  \(10^{12}\)(subproblems C1+C2);
  • to get 100 points, you need to solve the problem with constraints: n ≤  \(10^{18}\) (subproblems C1+C2+C3).

Output

Print a single integer — the minimum number of subtractions that turns the magic number to a zero.

Examples

input

Copy

24

output

Copy

5

Note

In the first test sample the minimum number of operations can be reached by the following sequence of subtractions:

24 → 20 → 18 → 10 → 9 → 0

思路

​ 题意:给定数字\(n\),每次减少该数的某个数位\(x\), 使得\(n = 0\), 求最小操作数

​ 首先我们能想到的是减去最大的数位,即\(f(x)\) 单调递增(数越小操作次数越小),那么如何证明这个方法是对的那?

​ 注. \(max(i)\)为\(i\)的最高数位

​ 可以用数学归纳法证明,首先当\(i < 10\)时,显然满足假设,当\(i > 10\)时, 我们考虑对于任意的\(i - 1\)和\(i\) ,我们分两种情况讨论,当\(i\)的最低位为\(0\)的时候,显然\(i - 1\)最高位为\(9\), 则 \(i - 1 - 9 < i - max(i)\), 当\(i\)的最低位大于0的时候, \(i\)与\(i - 1\)只有个位不同,显然\(i - 1 - max(i - 1) \le i - max(i)\), 所以有\(f(i - 1) \le f(i)\),即每次减去最大数位是正确的。

​ 当然上述思路对于\(1e18\)的数据并不能通过, 我们需要更好的方法, 即减少重叠子问题的计算 (dp)。

​ 我们可以考虑拆位来运算,具体做法是用字典记录\(\{<最大能减的数,当前数> , <最小操作数, 余数>\}\) 然后定义basecase后就能记忆化搜索。

​ 举例:将\(65\)拆分成先算\(60\)的结果和先算\(5\)的结果,以\(10854\)为例, 我们先拆分成\(10000\)和\(\{1, 854\}\)

和计算\(\{0, 10000 + 低位计算的余数\}\), 这里低位计算的余数指的是 对于\(98\)这种, 拆分成\(\{9, 8\}\) 和\(\{0, 90 + -1 = 89\}\)

code

#include <iostream>
#include <utility>
#include <map>
#define mk std::make_pair
#define ff first
#define ss second
typedef long long i64;
typedef std::pair<i64, i64> pii;

// dp字典存储 <最大能减的数,当前数> -> <最小操作数, 余数>
std::map<pii, pii> dp;

pii dfs(pii a) {
	// 如果当前数据<10, 直接返回答案, 注意到(0, 0) 的最小操作数还是0
	if(a.ss < 10)
		return mk(a.ss || a.ff, a.ss - std::max(a.ss, a.ff));

	// 找到数据直接返回<最小操作数, 余数>
	if(dp.find(a) != dp.end())
		return dp[a];

	// 截断最高位数字
	i64 p = 1;

	while(p <= a.ss / 10)
		p *= 10;

	// 低位运算
	pii b1 = dfs(mk(std::max(a.ff, a.ss / p), a.ss % p));

	// 高位运算
	pii b2 = dfs(mk(a.ff, a.ss / p * p + b1.ss));

	return dp[a] = mk(b1.ff + b2.ff, b2.ss);
}

int main() {
	i64 n;

	std::cin >> n;

	std::cout << dfs(mk(0, n)).ff;
}
posted on 2023-03-25 12:14  Jack404  阅读(20)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3