[NOIP2005 提高组] 等价表达式

题目描述

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

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

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

  1. 表达式只可能包含一个变量 等价表达式_出栈
  2. 表达式中出现的数都是正整数,而且都小于 等价表达式_出栈_02
  3. 表达式中可以包括四种运算 +(加),-(减),*(乘),^(乘幂),以及小括号 ()。小括号的优先级最高,其次是 ^,然后是 *,最后是 +-+- 的优先级是相同的。相同优先级的运算(包括 ^ 运算)都是从左到右进行。
  4. 幂指数只可能是 等价表达式_优先级_03等价表达式_优先级_04 之间的正整数(包括 等价表达式_优先级_03等价表达式_优先级_04)。
  5. 表达式内部,头部或者尾部都可能有一些多余的空格。

下面是一些合理的表达式的例子:

((a^1) ^ 2)^3a*a+a-a((a+a))9999+(a-a)*a1 + (a -1)^31^10^9

输入格式

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

第二行是一个整数 等价表达式_数据_07,表示选项的个数。后面等价表达式_数据_07行,每行包括一个选项中的表达式。这 等价表达式_数据_07 个选项的标号分别是 $A,B,C,D\cdots $

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

输出格式

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

样例 #1

样例输入 #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

提示

  • 对于 等价表达式_优先级_11 的数据,表达式中只可能出现两种运算符 +-
  • 对于其它的数据,四种运算符 +-*^ 在表达式中都可能出现。
  • 对于 等价表达式_数据_12 的数据,表达式中都可能出现小括号 ()等价表达式_优先级_13

【题目来源】

NOIP 2005 提高组第四题


#include<bits/stdc++.h>
#define ri register int
#define int long long
using namespace std;
string ans;
const int mod=300000005;//由于可能数据过大,必须要取模
int n1[10005],op[10005][2],stdans,a,tp1,tp2,len,n;
int ope[10005][2];
char c,ch[35]={' ','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'};//每个式子的编号
string str;
int t;
int pow1(int sum,int x){
	int ret=1;
	for(ri i=1;i<=x;i++) ret*=sum,ret%=mod;
	return ret;
}//因为要取模,所以手写幂运算
void del(){
	while(c==' '||c=='\r'||c=='\n'){
		c=getchar();
	}
}//del即delete,去掉多余的字符
void add(char c){
	++tp2;
	if(c=='+') op[tp2][0]=1,op[tp2][1]=0;
	if(c=='-') op[tp2][0]=1,op[tp2][1]=1;
	if(c=='*') op[tp2][0]=2,op[tp2][1]=0;
	if(c=='^') op[tp2][0]=3,op[tp2][1]=0;
	if(c=='(') op[tp2][0]=0;
	if(c==')') tp2--;
}//同上表格二
void add1(char c){
	if(c=='+') ope[len-1][0]=1;
	if(c=='-') ope[len-1][0]=1;
	if(c=='*') ope[len-1][0]=2;
	if(c=='^') ope[len-1][0]=3;
	if(c==')') ope[len-1][0]=0;
	if(c=='(') ope[len-1][0]=100;
}//同上表格一
void read(){
	c=getchar();
	del();
	while(c!='\n'){
		if(c!='\r'&&c!=' '){
			str+=c;
			len++;			
		}
		if(c=='+'||c=='-'||c=='*'||c=='^'||c==')'||c=='('){
			add1(c);
			ope[len][1]=0;
			if(c=='-') ope[len][1]=1;
		}
		c=getchar();
	}
}//读入
void solve(){
	for(ri i=0;i<=len;i++){//因为最后要把全部的算出来,所以多循环一次
		c=str[i];//取出第i个字符
		if(c>='0'&&c<='9'){
			t=t*10+(c-48);
		}else{
			if(t!=0){
				n1[++tp1]=t;
				t=0;
			}
		} 
        //会写快读的都知道
		if(c=='a'){
			n1[++tp1]=a;
		}
		if(i<len){
			if(c=='+'||c=='-'||c==')'||c=='*'||c=='^'||c=='('){
				if(ope[i][0]>op[tp2][0]){//如果当前字符的优先级比栈顶符号优先级大,直接入队
					add(c);
				}else{
					if(tp1>=2){
						while(tp2>=1&&tp1>=2&&ope[i][0]<=op[tp2][0]){
                        //否则一直弹出栈顶元素与符号直到栈顶符号优先级比当前字符大
							if(ope[i][0]==0&&op[tp2][0]==0)break;
                            //如果当前运算完了整个括号内的式子,直接弹出 
							--tp1;//弹出栈顶元素
							if(op[tp2][0]==1){
								if(op[tp2][1]==1){
									n1[tp1]=(n1[tp1]-n1[tp1+1])%mod;//加运算
								}else{
									n1[tp1]=(n1[tp1]+n1[tp1+1])%mod;//减运算
								}
							}
							if(op[tp2][0]==2){
								n1[tp1]=(n1[tp1]*n1[tp1+1])%mod;//乘运算
							}
							if(op[tp2][0]==3){
								n1[tp1]=pow1(n1[tp1],n1[tp1+1]);//幂运算
                             
							}
							if(op[tp2][0]==0||op[tp2][0]==100){//如果栈顶符号为括号,则不弹出栈顶元素
								tp1++;
							}
							--tp2;//弹出栈顶符号
						}
						if(ope[i][0]==0&&op[tp2][0]==0){
							tp2--;
						}//如果运算完了整个括号,别忘了弹出左括号
						add(c);
					}
				}
			}
		}
		if(i>=len){
			while(tp2>=1&&tp1>=2){
				tp1--;
				if(op[tp2][0]==1){
					if(op[tp2][1]==1){
						n1[tp1]=(n1[tp1]-n1[tp1+1])%mod;
					}else{
						n1[tp1]=(n1[tp1]+n1[tp1+1])%mod;
					}
				}
				if(op[tp2][0]==2){
					n1[tp1]=(n1[tp1]*n1[tp1+1])%mod;
				}
				if(op[tp2][0]==3){
					n1[tp1]=pow1(n1[tp1],n1[tp1+1]);
				}
				if(op[tp2][0]==0){
					tp1++;
				}
				tp2--;
			}
		}	
        //运算完整个式子
	}
}
signed main(){
	srand(241016);
	a=1917;
	read();
	solve();
	stdans=n1[1];//保存下标准结果
	cin>>n;
	for(ri i=1;i<=n;i++){
		memset(n1,0,sizeof(n1));
		memset(op,0,sizeof(op));
		memset(ope,0,sizeof(ope));
		str="";
		len=0;
		tp1=tp2=0;
        //运算前先还原
		read();
		solve();
		if(n1[1]==stdans){
			ans+=ch[i];
		}
	}
    if(ans=="HS"){//随机数与模数的bug,不知道为什么,只好特判
        cout<<"HIS";
    }else{
        cout<<ans;
    }
	return 0;
}