题意:
1425 减减数
1.0 秒 131,072.0 KB 80 分 5级题
初始给定一个整数n。每次可以对其做一个操作,这个操作是将n减去他其中的某一位。得到新的一个数字n’,然后继续操作,直到他变成0为止。
比如24这个例子,24 → 20 → 18 → 10 → 9 → 0
输入
单组测试数据。
第一行有一个整数n(0 ≤ n ≤ 10^12)
输出
输出一个整数表示使得n变成0最少的操作步数。.
输入样例
24
输出样例
5
思路:
1.我的想法:
首先,我们可以先看一下最朴素的算法,那么就是每次都进行分解数字,然后选择最大的数,删掉删掉,很明显n是1e12的范围,不能说一定会T掉,大概率会T掉。。。
然后就要想办法了,首先,我们应该明确肯定每次要减掉最大的,而且前面高位的最大值会对后面低位造成影响。比如1911,百位上的9会对十位上的1和个位上的1造成影响。
我是在哪里出错了呢,当然就是剩下的部分的处理出错了
2.我的想法
我本来是想搜索来着,但是是正着搜索,但是题目要求是这个操作是将n减去他其中的某一位。 但是好像判断有点困难,也不太行
3.正解:
没想到的就是真正解法就是倒着来搜索,记忆化搜索,
dfs(n , mx)表示当前要处理的数是n,mx是比n的最高位还要高的位的最大值
返回值是pair<long long , long long>类型的,first代表操作次数,second代表将该部分变为0中多余的部分。
记忆化搜索
代码实现:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<math.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
const int maxn = 2e5 + 5;
ll n;
map<pii,pii>mp;
pii dfs(ll n,ll mx){
//n表示的当前需要处理的数,mx是比n的最高位还要高的位的最大值
//返回值为pair类型,first表示操作次数,second表示将该部分变为0的过程中多余的部分
if(mp[make_pair(n,mx)].first) return mp[make_pair(n,mx)];
if(n < 10) return make_pair((n > 0)||(mx > 0),max(n,mx) - n);
ll m = 1;
while(m <= n / 10) m = m * 10;
ll p = n / m;
m = m * p;
pii a = dfs(n - m,max(p,mx)),b = dfs(m - a.second,mx);
return mp[make_pair(n,mx)] = make_pair(a.first + b.first,b.second);
}
int main(){
scanf("%lld",&n);
printf("%lld\n",dfs(n,0).first);
return 0;
}