luogu P9583 最大和 题解
题意(详细向)
对 \(T\) 个十进制数 \(n\) 进行 \(m\) 次操作,其中 \(m\) 是 \(n\) 的位数,\(m\) 在操作中(原题意不明,建议讲清爽)随着 \(n\) 的改变而改变。
操作有三种,假设某次操作为第 \(i\) 次操作,那么可以:
- 对 \(n\) 的第 \(i\) 位加 \(1\)。
- 对 \(n\) 的第 \(i\) 位减 \(1\)。
- \(n\) 不变。
思路(逐步向)
提示:普及组的题一定要往简单里想。。。
暴力:
先考虑用 DFS 暴力搜索,在递归中传递两个参数:\(dep\) 与 \(dat\),分别表示操作次数以及操作后的数值。
\(Q1\):如何求得一个数的位数?
\(A1\):对于一个数 \(n\),它在 \(k\) 进制下的位数是 \(\log_{k}n+1\)。另外注意:本题的位数随着操作实时更新。
\(Q2\):如何求得一个数的各位之和?
\(A2\):对于在 \(k\) 进制下的一个数 \(n\),求各位之和代码如下:
int tmp = 0;
while(n){
n += k % 10;
k /= 10;
}
理解了上面两个问题,那么整个暴力程序也就呼之欲出了——
下面的程序能够解决 30% 的数据。
(注意 \(n = 0\) 的特判,题目样例有提示。)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10004;
inline int Read();//快读,不展示了
int n,x,ans = 0;
void DFS(int dep,int dat){
if(dep > log10(dat) + 1){
//注意:要跟踪数值的变化来确定位数
int tmp = 0;
while(dat){//求各位之和
tmp += dat % 10;
dat /= 10;
}
ans = max(tmp,ans);
return;
}
int p = pow(10,dep - 1);
DFS(dep + 1,dat + p);//拓展
DFS(dep + 1,dat - p);
DFS(dep + 1,dat);
}
int main(){
n = Read();
for(int i = 1;i <= n;++i){
x = Read();
if(x <= 0){
puts("1");//特判
continue;
}
else{
ans = 0;
DFS(1,x);
printf("%d\n",ans);
}
}
return 0;
}
正解 贪心:
要使得每一位最大,我们必须对每一位逐步判断。
-
当前位的数码在 \(2\) 到 \(8\) 之间时,我们不难得到必须加上 \(1\)。否则减 \(1\) 没有用处,不变又没有贡献。
-
当前位的数码为 \(0\) 时,我们选择将这一位减去 \(1\)。否则加 \(1\) 并非最优,不变没有贡献。
-
当前位的数码为 \(9\) 时,不进行加减,保留不变。否则加 \(1\) 并非最优,减 \(1\) 适得其反。
大家可以手玩一下,也可以追踪之前的爆搜来验证,这样贪心的正确性不证自明。
于是我们就有了最终时间复杂度为 \(O(n)\) 的代码:
#include<bits/stdc++.h>\\根据标称改进
using namespace std;
inline int Read(){
char c = getchar();
int x = 0,f = 1;
while(c < '0' || c > '9'){
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
int main(){
int n = Read();
while(n--){
int a,sum = 0;
a = Read();
if(a == 0) sum = 1;//!!!
else{
while(a){
if(a % 10 == 0) a -= 1;
else if(a % 10 != 9) a += 1;
sum += a % 10;
a /= 10;
}
}
printf("%d\n",sum);
}
return 0;
}
结束力,觉得不错点个赞吧!

浙公网安备 33010602011771号