luogu P9583 最大和 题解

原题链接

题意(详细向)

\(T\) 个十进制数 \(n\) 进行 \(m\) 次操作,其中 \(m\)\(n\) 的位数,\(m\) 在操作中(原题意不明,建议讲清爽)随着 \(n\) 的改变而改变。

操作有三种,假设某次操作为第 \(i\) 次操作,那么可以:

  1. \(n\) 的第 \(i\) 位加 \(1\)
  2. \(n\) 的第 \(i\) 位减 \(1\)
  3. \(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;
}

正解 贪心:

要使得每一位最大,我们必须对每一位逐步判断。

  1. 当前位的数码在 \(2\)\(8\) 之间时,我们不难得到必须加上 \(1\)。否则减 \(1\) 没有用处,不变又没有贡献。

  2. 当前位的数码为 \(0\) 时,我们选择将这一位减去 \(1\)。否则加 \(1\) 并非最优,不变没有贡献。

  3. 当前位的数码为 \(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;
}

结束力,觉得不错点个赞吧!

posted @ 2023-08-23 09:36  CultReborn  阅读(17)  评论(0)    收藏  举报