2024.10.4 P1022 题解
模拟题,考验细心程度。捋清楚思路即可
由题意,本题实际上就是求解一个一元一次方程,而且运算符号只含有加减法,因此难度大大降低,无需考虑优先级。换言之,只需求出一次项系数
y 和常数之和x 即可求出ans= \frac{x}{y}
具体思路
-
一、首先找出 ‘’
= ‘’ 的下标位置,将字符串分为左右两部分 -
二、先求一次项系数的和
// 求一次项系数和 int fdsum(int x){ if(x==0) return 1; if (x==1) return (a[0] == '-') ? -1 : a[0]- '0'; int res = 0; int tmp = 0; int cnt = 1; for (int i = x - 1; i >= 0; i--){ if (a[i] >= '0' && a[i] <= '9') tmp += cnt * (a[i] - '0'),cnt *= 10; else{ if (a[i] == '-'){ if (tmp != 0) tmp -= 2*tmp; else {return -1;} } else{ if (tmp != 0){ res += tmp; return res; } else {return 1;} } break; } } res += tmp; return res; }
-
分别枚举字符串左部分,如果找到字母,则向前枚举元素,当元素不是数字时停止枚举,期间将各个数字拼接形成一个整数;右部分同理。
-
为了防止重复计算,要将枚举过的元素因删除(令
a_i= ' ')void todel(int st, int x){ for (int i = st; i > st-x; i--){ a[i] = ' '; } } -
令两部分的和为
sum1 和sum2 ,根据等式的性质, 显然sum2 应移项至左半部分,即y=sum1-sum2
// 处理未知项系数
int sum1 = 0, sum2 =0;
for (int i = 0; i < a.size();i++){
if (a[i] == '='){
nx = i;
break;
}
if (a[i] >= 'a' && a[i] <='z'){
sum1 += fdsum(i);
int t = fdlen(i);
todel(i, t);
}
}
int j = 0;
if (nx != -1){
for (int i = nx; i <a.size(); i++){
if (a[i] == '-' && (a[i+1] >= 'a' && a[i+1] <= 'z')) a[i] = '+';
else if (a[i] == '+' && (a[i+1] >= 'a' && a[i+1] <= 'z')) a[i] = '-';
if (a[i] >= 'a' && a[i] <='z'){
sum2 += fdsum(i);
int t = fdlen(i);
todel(i, t);
}
}
}
y = sum1-sum2;
-
三、再求常数项的和
- 大体上与求一次项系数的和相同,但需要注意的是:(1)
fdsum 函数需要根据数字的特性进行修改,如遇到+ 、- 号的情况需要特判等
- 大体上与求一次项系数的和相同,但需要注意的是:(1)
// 求常数系数和
int fdsum2(int x){
if(x==0) return a[0] - '0';
if (x==1) {
if (a[0] == '-') return (a[1]-'0') - 2*(a[1]-'0');
}
int res = 0,tmp = 0,cnt = 1;
for (int i = x; i >= 0; i--){
if (a[i] >= '0' && a[i] <= '9') tmp += cnt * (a[i] - '0'),cnt *= 10;
else{
if (a[i] == '-'){
if (tmp != 0) tmp -= 2*tmp;
else return 0;
}
else{
if (tmp == 0) return res;
}
}
}
res += tmp;
return res;
}
(2)枚举左半部分常数元素时应确保以常数的最后一位数字开始向左枚举。即:对于…+36=……,应从6开始向左枚举而不是从3开始向左枚举。为了处理这个问题,可以多加一个特判:
if (a[i] >= '0' && a[i] <= '9' && (a[i+1] < '0' || a[i+1] > '9'))
- 同求一次项系数思路,令左半部分之和为
sum3 右半部分为sum4 根据等式的性质, 显然sum3 应移项至右半部分,即x=sum4-sum3
//处理常数项:将等号两边常数求和,用右边的减左边的
int sum3 = 0, sum4 = 0; // the sum of leftSide & RightSide
// leftSide
for (int i = 0; i < nx; i++){
if (a[i] >= '0' && a[i] <= '9' && (a[i+1] < '0' || a[i+1] > '9')){
sum3 += fdsum2(i);
int t = fdlen(i);
todel(i,t);
}
}
// rightSide
for (int i = a.size() - 1; i >= nx+1; i--){
if (a[i] >= '0' && a[i] <= '9'){
sum4 += fdsum2(i);
int t = fdlen(i);
todel(i,t);
}
}
x = sum4-sum3;
-
四、综上,所需的 一次项系数之和
y 与常数项之和x 已经求出,现在只需计算答案即可
ans = (y == 0) ? 0 : (double)x / (double)y;
printf("%c=%.3lf\n", ch,ans);