vijos p1003 等价表达式 题解

时间:2021-12-27 14:37:50

题目描述 Description

明明进了中学之后,学到了代数表达式。有一天,他碰到一个很麻烦的选择题。这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的。

这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题。假设你是明明,能完成这个任务吗?

这个选择题中的每个表达式都满足下面的性质:
1
表达式只可能包含一个变量a
2
表达式中出现的数都是正整数,而且都小于10000
3
表达式中可以包括四种运算+(加),-(减),*(乘),^(乘幂),以及小括号()。小括号的优先级最高,其次是^,然后是*,最后是+-+-的优先级是相同的。相同优先级的运算从左到右进行。(注意:运算符+-*^以及小括号()都是英文字符)
4
幂指数只可能是110之间的正整数(包括110)。
5
表达式内部,头部或者尾部都可能有一些多余的空格。
下面是一些合理的表达式的例子:
((a^1)^2)^3
a*a+a-a((a+a))9999+(a-a)*a1+(a-1)^31^10^9……

输入描述 Input Description

输入第一行给出的是题干中的表达式。第二行是一个整数n2<=n<=26),表示选项的个数。后面n行,每行包括一个选项中的表达式。这n个选项的标号分别是ABCD……

输入中的表达式的长度都不超过50个字符,而且保证选项中总有表达式和题干中的表达式是等价的。

输出描述 Output Description

输出包括一行,这一行包括一系列选项的标号,表示哪些选项是和题干中的表达式等价的。选项的标号按照字母顺序排列,而且之间没有空格。

样例输入 Sample Input

(a+1)^2
3
(a-1)^2+4*a
a+1+a
a^2+2*a*1+1^2+10-10+a-a

样例输出 Sample Output

AC

数据范围及提示 Data Size & Hint

【数据规模】
对于30%的数据,表达式中只可能出现两种运算符+-
对于其它的数据,四种运算符+-*^在表达式中都可能出现。
对于全部的数据,表达式中都可能出现小括号()

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

这道题很坑爹,在codevs上的数据永远都是RC 6个点,但是vijos上却可以ac……难不成vijos数据很弱??

言归正传,这道题是一道处理字符串中缀表达式的问题,我们先要把中缀转化为后缀,然后在进行计算(具体方法请看我的前/中/后缀的那些事儿

但是a如何处理呢?没错就是带一个比较特异的数,然后枚举计算,如果值相同,那么我们就说这两个式子相同。至于什么叫特异的数,我觉得3就是很好的一个,毕竟数值小,而且还是质数,所以我用的是3。当然,其实还存在一个比较坑爹的地方,就是如果你代值,那么有一些数会爆long long,所以要mod一个大质数。

至于详细题解,看代码吧,基本上重要的地方都有标注了……

友情提示:最好不要在codevs交这道题,因为你会呵呵呵的……当然如果你在codevs上a了这题,请留言,并附加代码,笔者真的很想知道为什么会rc……谢谢

+++++++++++++++++++++++++++代码如下++++++++++++++++++++++++++++++++++++++++

<span style="font-family:Comic Sans MS;font-size:18px;">#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <stack>
#include <vector>
#define p 1000007
using namespace std;
const char b[27]={'0','A','B','C','D','E','F','G',
'H','I','J','K','L','M','N','O',
'P','Q','R','S','T','U','V','W',
'X','Y','Z'};//这里其实不用这么麻烦的,我一开始怕错,不敢写ASII码的
string ss;
long long n,aim;
stack <char> ope;

long long strnum(string s) //字符串转成long long
{
long long num;
stringstream ss(s);
ss>>num;
return num;
}

int pre(char a)//定义优先级
{
if(a=='='||a=='(')return 0;
if(a=='+'||a=='-')return 1;
if(a=='*')return 2;
if(a=='^')return 3;
}
long long sta[555555],top;//手打栈,一开始怎么测都是访问无效内存,然后就想换成stl的,后来才知道好像数据有些问题,太坑爹了
long long work(string s)//计算后缀
{
string ss;
ss="";//注意,要把ss清空
memset(sta,0,sizeof(sta));top=0;//注意要把栈清空
for(int i=0;i<s.size();i++)
{
if(s[i]>='0'&&s[i]<='9')
ss+=s[i];
else
{
if(s[i]==' ')
{
top++;
sta[top]=strnum(ss)%p;//坑了我很长时间,最后看了数据才知道原来是超long long 了
ss="";//但要注意,最好不要在下面mod,因为那样很容易错,所以干脆就在一开始就mod
}
else
{
if(s[i]=='-')
{
long long s1,s2;
s2=sta[top];
if(top>0)
{top--;
s1=sta[top];
s1=s1-s2;
sta[top]=s1;}
continue;
}
if(s[i]=='+')
{
long long s1,s2;
s2=sta[top];
if(top>0)
{top--;
s1=sta[top];
s1=s1+s2;
sta[top]=s1;}
continue;

}
if(s[i]=='*')
{
long long s1,s2;
s1=sta[top];if(top>0) top--;
s2=sta[top];
s1=s1*s2;
sta[top]=s1;
continue;
}
if(s[i]=='^')
{
long long s1,s2;
s1=sta[top];if(top>0) top--;
s2=sta[top];
long long z=1LL;
for(int i=1;i<=s1;i++)
z=z*s2;
sta[top]=z;
continue;
}
}
}
}if(top==0)return strnum(ss);
else return sta[top];
}

string change(string str)//中缀转后缀
{
while(!ope.empty())
ope.pop();
string s;
s.clear();//这些初始化都是必要的
ope.push('='); //这里的“= ”最好加上,比较方便
int len = str.length();
for(int i = 0 ; i < len; ++i)
{
if(str[i] >= '0' && str[i] <= '9')s+=str[i];//处理数字
else
{
if(str[i-1] >= '0' && str[i-1] <= '9')s+=' ';//为了避免如102 2变为1 0 2 2的情况,本人在中缀转后缀时 ,把两个数字之间<span style="white-space:pre"></span>//加上了空格
if(str[i] == '(')
ope.push(str[i]);
else if(str[i] == ')')
{
while (ope.top() != '(')
{
s+=ope.top();
ope.pop();
}
ope.pop();
}
else if(pre(str[i]) > pre(ope.top())) ope.push(str[i]);
else
{
while(pre(str[i]) <= pre(ope.top()))
{
s+=ope.top();
ope.pop();
}
ope.push(str[i]);
}
}
}
while(ope.top() != '=')
{
if(s[s.size()-1]>= '0' && s[s.size()-1]<= '9')s+=' ';
s+=ope.top();
ope.pop();
}
return s;
}

int main()
{
string sss;
getline(cin,sss);
for(int i=0;i<sss.size();i++)
if(sss[i]!=' ')ss+=sss[i];
cin>>n;getchar();
for(int i=0;i<ss.size();i++)
if(ss[i]=='a')ss[i]='3';
long long aim=work(change(ss));
for(int i=1;i<=n;i++)
{
string s,s2;
getline(cin,s2);
for(int j=0;j<s2.size();j++)
if(s2[j]!=' ')s+=s2[j];
for(int j=0;j<s.size();j++)
if(s[j]=='a')s[j]='3';
long long z=work(change(s));
if(aim==z)cout<<b[i];
}cout<<endl;
return 0;
}</span>