CF952F 2 + 2 != 4 题解


思路

首先把题干丢进翻译,发现并没有什么作用。

1.1 题目意义的分析

所以可以分析一下 \(2+2=-46\) 的小样例看能不能从中得到什么信息。

利用简单的数学计算出 \(2+2=4\),和我们需要的答案差了 \(50\)。所以可以这样想,在这个题目里 \(+2\) 等同于 \(-48\)

恰好,\(-48=-50+2\),所以考虑多出来的 \(-50\) 是哪里来的。

转变一下思路可以想到这个 \(-48\) 相当于一个十位为 \(-5\),个位为 \(2\) 的数。

所以考虑这个 \(-5\) 从哪来的。在刚刚的推导中,第二个 \(2\) 已经被用了,所以这个 \(-5\) 应该是从那个加号来的。

很容易想到要把字符对应到数,是 ASCII 码。而加号的 ASCII 码是 \(43\)。突然想到 \(0\) 的 ASCII 码是 \(48\)

所以题目是把符号当成了数字加入计算,在普通的计算表达式值的过程中,从字符串转到数时要把符号减去 \(48\) 得到的数作为最高位,就像处理普通的数字一样。当然如果前面的符号是加号,就加上我们处理出的数,是减号就减去我们处理出的数。

1.2 代码思路的分析

普通的表达式求值是遇到字符串中的数,就把数变成 \(\texttt{int}\) 加入计算,所以我们可以采取换汤不换药的方法,遇到一个数,先判断前面的符号,将记录数值的变量赋初值为前一个符号的 ASCII 码减掉 \(48\) 的值(而不是 \(0\))。

这是唯一的不同。其他就是正常的表达式求值。

代码

2.1 初始处理

因为我们是遇到数就往前看符号,而第一个数前面并没有符号,所以首先把第一个数取出来。

要用一个变量记录第一个数的长度,因为下一步操作要从第二个数开始。

最后记得把存数值的变量清空。

for(int i=0;i='0'&&s[i]<='9'){
		sum*=10;
		sum+=s[i]-'0';//非常正常的字符串转数
		k=i;//下一步操作要从下一个数开始,所以记录第一个数的长度
	}	
	else{//我们只需要第一个数
		break;
	}
}
ans=sum;
sum=0;

2.2 处理字符串中单数的值

首先要判断这个位置是一个数字,这个不用多说。

接着要看是什么符号以分开处理。当前面的符号是加号的时候初值就是 \(43-48\);是减号的时候初值就是 \(45-48\)。为了不打成两个if把中间相同的字符串转数部分写两遍,可以使用三目运算符。因此我们可以把给存数变量赋初值的部分写成:

sum=(s[i-1]=='-'?'-':'+')-'0';

还可以把最后给总答案加减值的部分写成:

s[f-1]=='-'?ans-=sum:ans+=sum;

(因为我们要在字符串转数的时候改变原本的 \(i\),所以用 \(f\) 存这个数开始的位置)

中间则是一个字符串转数的模板:

for(int j=i;j='0'&&s[j]<='9'){
		sum*=10;
		sum+=s[j]-'0';
		i=j;//来一个数字往后面动一位,直到没有数字的时候,i 将会指向这个数后面的符号的前一个位置,而外层循环还有一个 i++。
	}
	else{//我们只要数,不要符号
		break;
	}
}

AC 记录

代码不放了,防止抄题解,而且文章里面都给的很明白。

AC 记录

相关