2024年3月7日发(作者:)

2.表达式求值

(/c/pas)

【问题描述】

给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。

【输入】

输入文件为。

输入仅有一行,为需要你计算的表达式,表达式中只包含数字、加法运算符“+”和乘法运算符“*”,且没有括号,所有参与运算的数字均为0到231-1之间的整数。输入数据保证这一行只有0~ 9、+、*这12种字符。

【输出】

输出文件名为。

输出只有一行,包含一个整数,表示这个表达式的值。注意:当答案长度多于4位时,请只输出最后4位,前导0不输出。

【输入输出样例1】

1+1*3+4 8

【输入输出样例2】

1+1234567890*1 7891

【输入输出样例3】

1+1000000003*1

4

【输入输出样例说明】

样例1计算的结果为8,直接输出8。

样例2计算的结果为1234567891,输出后4位,即7891。

样例3计算的结果为1000000004,输出后4位,即4。

【数据范围】

对于30%的数据,0≤表达式中加法运算符和乘法运算符的总数≤100;

对于80%的数据,0≤表达式中加法运算符和乘法运算符的总数≤1000;

对于100%的数据,0≤表达式中加法运算符和乘法运算符的总数≤100000。

这道题我看了一下,全市一百三十多人中,得一百分的只有三十多人,二十来人得了八九十分,其余的,绝大多数只有一二十分。其实,这题并不难,只是烦些,算法及其实现有很多种。作为两校中唯一一个此题全过的,我希望能与大家分享我的思路与算法。

初看这个题目,第一反应是字符串处理+高精度。我是一个水货,

这两方面非常不熟,当时就懵了。回过神后,再仔细看题,发现表达式内的数据都不超过longint范围,且只要输出后四位,甚至不用高位补“0”,这才发现,此题其实挺简单的。万变不离模拟法,我的算法出炉了。

a

c

1

+

2

*

2

*

2

+

1234

如图所示,设一个长整形数组a存数据,一个字符数组c存符号。符号与数据错开来存。i从1扫描至最后,其间若c[i]=’*’,则令a[i+1]:=a[i-1]*a[i+1], a[i-1]:=0,以解决连乘问题。最后,再次扫描数组a,将已有数据累加、取余,输出结果。以图为例,当i=4时,a[5]:=a[3]*a[5]=4,a[3]:=0,以此类推,得a[7]=8。最后(1+8+1234)mod 10000,输出1243。要注意的是,运算中要随时取余,避免一切可能的数据溢出。

程序:

var st:string;

a:array[1..20000000]of longint;

c:array[1..20000000]of char;//我的数组可能开得有些大

k,j,l,i,x:longint;

n,s:qword;ch:char;

begin

assign(input,'');

reset(input);

assign(output,'');

rewrite(output);

i:=0;s:=0;st:='';

while not eoln do//使用字符串读入

begin

read(ch);

st:=st+ch;

if(ch='*')or(ch='+')or(ch=' ')then

begin

inc(i);

val(copy(st,1,length(st)-1),a[i],x);

inc(i);c[i]:=ch;//错开存放

st:='';

end;

end;

inc(i);

val(st,a[i],x);

l:=i;

for i:=1 to l do

begin

k:=i;

if c[k]='*' then

begin

n:=(a[k-1] mod 10000)*(a[k+1] mod 10000);//随时取余

c[k]:=' ';a[k-1]:=0;a[k+1]:=n;

end;

end;

for i:=1 to l do

s:=(s+a[i]) mod 10000;

writeln(s);

close(input);

close(output);

end.

此程序测试结果如下:

时间复杂度为O(n),通过所有测试点总用时不到0.1s。空间复杂度为O(2n),内存消耗较多可能是数组开太大的缘故。程序较简短,源文件仅有1kB。

这就是我的算法与思路。希望得到大家的改进意见。