洛谷 P1054等价表达式题解--zhengjun

题目描述

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

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

这个选择题中的每个表达式都满足下面的性质:

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

((a^1) ^ 2)^3,a*a+a-a,((a+a)),9999+(a-a)*a,1 + (a -1)^3,1^10^9………

输入格式

第一行给出的是题干中的表达式。

第二行是一个整数\(n(2 \le n \le 26)\),表示选项的个数。后面\(n\)行,每行包括一个选项中的表达式。这\(n\)个选项的标号分别是\(A,B,C,D\cdots\)

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

输出格式

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

输入输出样例

输入 #1 复制
( a + 1) ^2
3
(a-1)^2+4*a
a + 1+ a
a^2 + 2 * a * 1 + 1^2 + 10 -10 +a -a
输出 #1 复制
AC

说明/提示

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

\(2005\)年提高组第四题

思路

特别想吐槽一下这道题

数据又特别水,值还很大,题目中没说表达式的括号一定匹配,所以要判断,我无语了

首先,我判断两个表达式相等的依据就是代入不同的值,如果结果都一样,那么这两个表达式就是等价的。如果还没有学过表达式求值的话,建议先去看看栈的实现。

然后,这道题的数据水到什么程度,我代特值,只要代一个\(1\),就可以得到\(80\)分,然后,代两个\(1,2\)就满分了,我谔谔,答案还特别大,需要取模,告诉你我取模是靠传说中的\(rand()\),真香。

代码

#include<bits/stdc++.h>
using namespace std;
int mod;
/********以下是表达式求值********/
map<char,int> p;
int a[1001],aa,bb;
char b[1001];
void init(){
	p['+']=1;
	p['-']=1;
	p['*']=2;
	p['/']=2;
	p['^']=3;
	p['(']=0;
	p[')']=0;
	p['=']=-1;
}
int pow(int x,int y){//快速幂,不然TEL
	int ans=1,cnt=x;
	while(y){
		if(y&1)ans=ans*cnt%mod;
		cnt=cnt*cnt%mod;
		y>>=1;
	}
	return ans;
}
void js(){
	char s=b[bb--];
	int x=a[aa--],y=a[aa--],z;
	switch(s){
		case '+':{z=y+x;z%=mod;break;}
		case '-':{z=y-x;z%=mod;break;}
		case '*':{z=y*x;z%=mod;break;}
		case '/':{z=y/x;z%=mod;break;}
		case '^':{z=pow(y,x);z%=mod;break;}
	}
	a[++aa]=z;
}
int get(string s,int k){
	int len,i=0;
	s+='=';
	len=s.length();
	aa=bb=0;
	while(i<len){
		if(s[i]==' '){i++;continue;}
		if(s[i]=='a'){a[++aa]=k;i++;continue;}
		if(s[i]>='0'&&s[i]<='9'){
			int x=s[i++]-'0';
			while(s[i]>='0'&&s[i]<='9')x=x*10+s[i++]-'0';
			a[++aa]=x;
			continue;
		}
		if(s[i]=='('){b[++bb]=s[i++];continue;}
		while(bb>0&&p[s[i]]<=p[b[bb]]){
			if(s[i]==')'&&b[bb]=='('){bb--;break;}
			js();
		}
		if(s[i]!=')')b[++bb]=s[i];
		i++;
	}
	return a[1];
}
/********以上是表达式求值********/
bool check(string s){//判断括号匹配
	int top=0,len=s.length();
	for(int i=0;i<len;i++){
		if(s[i]=='(')top++;
		if(s[i]==')')top--;
		if(top<0)return 0;
	}
	return top==0;
}
int main(){
	init();
	srand(time(0));
	mod=rand()%50000+100;//精髓
	int n;
	string s;
	getline(cin,s);
	int x[5];
	for(int i=1;i<4;i++)x[i]=get(s,i);
	scanf("%d\n",&n);//要过滤一个换行
	string ans;
	for(int i=1;i<=n;i++){
		getline(cin,s);
		if(!check(s))continue;
		int j;
		for(j=1;j<4;j++)if(get(s,j)!=x[j])break;
		if(j==4)ans+=char('A'+i-1);
	}
	cout<<ans;
	return 0;
}

谢谢--zhengjun

posted @ 2022-06-10 19:19  A_zjzj  阅读(35)  评论(0编辑  收藏  举报