Educational Codeforces Round 121 1626B Minor Reduction

题目描述(传送门)

Educational Codeforces Round 121 1626B Minor Reduction_第1张图片

题目翻译:

给你一个十进制数x,高位没有多余的0。你需要对其执行一次操作:将x中两个相邻的数替换成它们的和(它们的和的高位也不能有多余的0,比如如果和是9,就用9来替换,而不是09;如果和是0,则用0来替换,而不是00)
比如,如果x = 10057,则可能的结果是:

  • 选择第一位数1和第二位数0,用1+0=1来替换,则结果是1057;
  • 选择第二位数0和第三位数0,用0+0=0来替换,则结果也是1057;
  • 选择第三位数0和第四位数5,用0+5=5来替换,则结果仍然是1057;
  • 选择第四位数5和第五位数7,用5+7=12来替换,则结果是10012;

问能得到的最大的数是几?

解题思路:

令取得的两位数为a(允许a的高位有多余的0,比如a = 09,a = 00),a的个位数和十位数相加等于b
首先可以发现, a ≥ b。证明如下:

不管a取何值,b ≤ 18(b最大的情况是:当a = 99时,b = 18)。
因此,当18<a ≤ 99时,a>b,命题成立;
当10 ≤ a ≤ 18时,b ≤ 9,而a ≥ 10,故a>b,命题成立;
当0 ≤ a ≤ 9时,a = b,命题成立。

从上面的证明也可以发现,当a ≥ 10时,a > b(而非a ≥ b)

对两位数进行上面的操作,其位数变化会有两种情况:①位数减一(如11->2);②位数不变(如56->11)。为了使结果尽可能地大,显然第②种情况得到的结果比第①种情况得到的结果要大。然后对这两种情况进行分类讨论:1、根据上面的证明可以知道,当位数不变时,说明取得的a ≥ 10,而当a ≥ 10时,a > b,这说明操作过后,a会变小。而如果a在x的高位,其变小会使得x的值降得更多,所以我们应当选择处于x的低位的a。2、当位数减一时,b ≥ a的十位,若a在x的高位,a的变化会使得x的值增得更多,所以这时要优先选择处于x的高位的a。若此时a的十位=b,我们应当继续遍历,还是直接选择该位置的a呢?这种情况下,a只能是10,以x=1000011来举例,若继续向后遍历,试图找到一个a的十位 总得来说,先从x的低位向高位遍历,若找到一个位数不变的情况,直接输出结果;若遍历完后未发现位数不变的情况,则直接对高位的两位进行上述操作,得出结果。

代码:
#include
#include
using namespace std;
string operate(string s,int i) { //对数中第i位和第i+1位进行操作
	int a,b,c,d;
	string add="";
	a=s[i]-'0',b=s[i+1]-'0',c=(a+b)/10,d=(a+b)%10;
	if(c!=0) add=add+char('0'+c);
	add=add+char('0'+d);
	if(i<=s.size()-3) return s.substr(0,i)+add+s.substr(i+2,s.size()-(i+2));
	else return s.substr(0,i)+add;
}
int main() {
//	freopen("1.txt","r",stdin);
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,a,b;
	string s;
	cin>>n;
	while(n--) {
		cin>>s;
		bool flag=false;
		for(int i=s.size()-2;i>=0;i--){
			a=s[i]-'0',b=s[i+1]-'0';
			if(a+b>=10){
				cout<<operate(s,i)<<endl;
				flag=true;
				break;
			}
		}
		if(!flag) cout<<operate(s,0)<<endl;
	}
}
总结:

分析太重要了,一直到写博客,才知道有很多地方都没分析明白,最开始做出来也存在着侥幸。

你可能感兴趣的:(codeforces,ACM,c++,codeforces,acm竞赛)