洛谷P1054等價表達式題解--zhengjun

題目描述

明明進了中學之後,學到了代數表達式。有一天,他碰到一個很麻煩的選擇題。這個題目的題幹中首先給出了一個代數表達式,然後列出了若干選項,每個選項也是一個代數表達式,題目的要求是判斷選項中哪些代數表達式是和題幹中的表達式等價的。

這個題目手算很麻煩,因爲明明對計算機編程很感興趣,所以他想是不是可以用計算機來解決這個問題。假設你是明明,能完成這個任務嗎?

這個選擇題中的每個表達式都滿足下面的性質:

表達式只可能包含一個變量‘aa’。
表達式中出現的數都是正整數,而且都小於1000010000
表達式中可以包括四種運算++(加),-(減),*(乘),^ (乘冪),以及小括號((,))。小括號的優先級最高,其次是^ ,然後是*,最後是++-++-的優先級是相同的。相同優先級的運算從左到右進行。(注意:運算符++-*,^ 以及小括號(())都是英文字符)
冪指數只可能是111010之間的正整數(包括111010)。
表達式內部,頭部或者尾部都可能有一些多餘的空格。
下面是一些合理的表達式的例子:

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

輸入格式

第一行給出的是題幹中的表達式。

第二行是一個整數n(2n26)n(2 \le n \le 26),表示選項的個數。後面nn行,每行包括一個選項中的表達式。這nn個選項的標號分別是A,B,C,DA,B,C,D\cdots

輸入中的表達式的長度都不超過5050個字符,而且保證選項中總有表達式和題幹中的表達式是等價的。

輸出格式

一行,包括一系列選項的標號,表示哪些選項是和題幹中的表達式等價的。選項的標號按照字母順序排列,而且之間沒有空格。

輸入輸出樣例

輸入 #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%30\%的數據,表達式中只可能出現兩種運算符++-
對於其它的數據,四種運算符++-*,^ 在表達式中都可能出現。
對於全部的數據,表達式中都可能出現小括號(())

20052005年提高組第四題

思路

特別想吐槽一下這道題

數據又特別水,值還很大,題目中沒說表達式的括號一定匹配,所以要判斷,我無語了

首先,我判斷兩個表達式相等的依據就是代入不同的值,如果結果都一樣,那麼這兩個表達式就是等價的。如果還沒有學過表達式求值的話,建議先去看看棧的實現。

然後,這道題的數據水到什麼程度,我代特值,只要代一個11,就可以得到8080分,然後,代兩個1,21,2就滿分了,我諤諤,答案還特別大,需要取模,告訴你我取模是靠傳說中的rand()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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章