原文在这里:https://www.luogu.org/problemnew/show/P1981
好吧又是洛谷的。。。
首先,这道题很简单,由于只有乘法和加法两种运算,竟然还没有括号!!!简直就是普及组的奇迹!!!直接模拟不就好了?
直接上代码:
#include
#include
#include
#include
#include
#include
using namespace std;
const int mod=10000;
string s;
long long now=0,result=0,time=1;
bool isTime=false;
int main()
{
freopen("expr.in","r",stdin);
freopen("expr.out","w",stdout);
cin>>s;
int len=s.length();
for(int i=0;iswitch(s[i]){
case '+':{
if(isTime==true){
result+=time*now;
result=result%mod;
isTime=false;
time=1;
}
else{
result+=now;
result=result%mod;
}
now=0;
break;
}
case '*':{
time*=now;
time%=mod;
isTime=true;
now=0;
break;
}
default:{
if((s[i]>='0')&&(s[i]<='9'))
now=(now*10+s[i]-'0')%mod;
break;
}
}
}
if(isTime){
result+=time*now;
result=result%10000;
}
else{
result+=now;
result=result%10000;
}
cout<return 0;
}
好了,如果单纯只是想了解这道题的做法的童鞋在这里就可以止步了。接下来,我们要推广到有加减乘除四则运算以及有括号参与的计算了。
在这里介绍两种方法:
1.用栈来实现:
首先用一个栈来存储数字,用一个栈来存储符号。如果进来的是左括号,那么先放着不做处理,如果进来的是加号和减号,就直接做到小括号为止。如果是乘号和除号,就做到第一个级别比他小的地方或者左括号为止。如果进来的是右括号,那么做到第一个左括号为止,并且删去该左括号,直到做到结束。这样在存数字的栈中唯一剩余的那一个数就是答案。
如果还是有点懵逼的童鞋可以看程序理解一下:
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxN=100100;
const int mod=10000;
string s;
long long op1[maxN];
char op2[maxN];
int num1,num2;
void handle()
{
switch(op2[num2]){
case '+':
op1[num1-1]=(op1[num1-1]+op1[num1])%mod;
num1--;
break;
case '-':
op1[num1-1]=(op1[num1-1]-op1[num1])%mod;
num1--;
break;
case '*':
op1[num1-1]=(op1[num1-1]*op1[num1])%mod;
num1--;
break;
case '/':
op1[num1-1]=(op1[num1-1]/op1[num1])%mod;
num1--;
break;
}
}
void work1()
{
while(num2>0&&op2[num2]!='('){
handle();
num2--;
}
}
void work2()
{
while(num2>0&&(op2[num2]=='*'||op2[num2]=='/')){
handle();
num2--;
}
}
int main()
{
//freopen("expr.in","r",stdin);
//freopen("expr.out","w",stdout);
cin>>s;
int len=s.length();
int i=0;
while(iif(s[i]<='9'&&s[i]>'0'){
long long temp=0;
while(i='0'&&s[i]<='9'){
temp=(temp*10+s[i]-'0')%mod;
i++;
}
num1++;
op1[num1]=temp;
}
if(i==len)
break;
switch(s[i]){
case '+':
case '-':
work1();
op2[++num2]=s[i];
break;
case '*':
case '/':
work2();
op2[++num2]=s[i];
break;
case '(':
op2[++num2]=s[i];
break;
case ')':
work1();
num2--;
break;
}
++i;
cout<for(int i=1;i<=num1;++i)
cout<" ";
cout<cout<for(int i=1;i<=num2;++i)
cout<" ";
cout<cout<1]<return 0;
}
2.递归
说实话,用栈来实现比用递归来实现要快多了,但是为了锻炼自己,还是要每一种方法都要写一下。
先讲一下思路吧:首先我们要找到最后一次运算的符号在哪里,并且从这分开,在他的左右两边去寻找各自区间的最后运算的符号在哪里,然后以此类推,直到这个区间所有的都是数字为止。
首先,我们要解决括号配对的问题。我们依然可以用栈的思想来实现,并且我们还要记录每一个点他外面所拥有的括号层数,以此来判断是否为最后一次运算的符号。说完思路,可能大家还是有点蒙蒙的,举一个栗子好了:
假如说我们要计算 (1+2)*3 的值
用栈将 s[0] 的左括号和 s[4] 的右括号匹配,s[1]到s[3]的外层括号数都为1
首先递归0到(len-1)寻找最后做的运算符号,发现是s[5]的乘号,所以再递归两边的最后的符号,即递归0到4,和递归6到6,将二者的值乘起来就是答案。
下面考虑6到6:由于是一个数字,所以结束递推,返回值s[6]
再来考虑0到4:由于s[0]和s[4]是一对匹配的左右括号,所以直接考虑1到3,1+2…这个就不必再往下了吧?
最后附上代码~~~
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxN=100100;
string s;
int len,ans,stack[maxN],stacknum=0,kuo[maxN],kuonum=0;
int peidui[maxN];
bool isDigit(int l,int r)
{
for(int i=l;i<=r;++i){
if(s[i]<'0'||s[i]>'9')
return false;
}
return true;
}
int dg(int l,int r)
{
if(isDigit(l,r)){
int t=s[l]-'0';
for(int i=l+1;i<=r;++i)
t=t*10+s[i]-'0';
return t;
}
if(peidui[l]==r){
for(int i=l+1;i<=r-1;++i)
kuo[i]--;
return dg(l+1,r-1);
}
char p='.';
int p1=-1;
for(int i=l+1;i<=r-1;++i){
switch(s[i]){
case '+':
case '-':
if(kuo[i]==0){
p=s[i];
p1=i;
}
break;
case '*':
case '/':
if(kuo[i]==0){
if(p1==-1){
p1=i;
p=s[i];
}
else{
if(p=='*'||p=='/'){
p1=i;
p=s[i];
}
}
}
break;
}
}
switch(p){
case '+':
return dg(l,p1-1)+dg(p1+1,r);
case '-':
return dg(l,p1-1)-dg(p1+1,r);
case '/':
return dg(l,p1-1)/dg(p1+1,r);
case '*':
return dg(l,p1-1)*dg(p1+1,r);
}
}
int main()
{
cin>>s;
len=s.size();
for(int i=0;iif(s[i]=='('){
stack[++stacknum]=i;
kuonum++;
kuo[i]=-1;
continue;
}
if(s[i]==')'){
peidui[stack[stacknum]]=i;
peidui[i]=stack[stacknum];
stacknum--;
kuonum--;
continue;
}
kuo[i]=kuonum;
}
cout<0,len-1)<return 0;
}