等價表達式 2005年NOIP全國聯賽提高組(棧模擬)
P1054 等價表達式
題目描述
明明進了中學之後,學到了代數表達式。有一天,他碰到一個很麻煩的選擇題。這個題目的題幹中首先給出了一個代數表達式,然後列出了若幹選項,每個選項也是一個代數表達式,題目的要求是判斷選項中哪些代數表達式是和題幹中的表達式等價的。
這個題目手算很麻煩,因為明明對計算機編程很感興趣,所以他想是不是可以用計算機來解決這個問題。假設你是明明,能完成這個任務嗎?
這個選擇題中的每個表達式都滿足下面的性質:
1. 表達式只可能包含一個變量‘a’。
2. 表達式中出現的數都是正整數,而且都小於10000。
3. 表達式中可以包括四種運算‘+’(加),‘-’(減),‘*’(乘),‘^’(乘冪),以及小括號‘(’,‘)’。小括號的優先級最高,其次是‘^’,然後是‘*’,最後是‘+’和‘-’。‘+’和‘-’的優先級是相同的。相同優先級的運算從左到右進行。(註意:運算符‘+’,‘-’,‘*’,‘^’以及小括號‘(’,‘)’都是英文字符)
4. 冪指數只可能是1到10之間的正整數(包括1和10)。
5. 表達式內部,頭部或者尾部都可能有一些多余的空格。
下面是一些合理的表達式的例子:
((a^1) ^ 2)^3,a*a+a-a,((a+a)),9999+(a-a)*a,1 + (a -1)^3,1^10^9……
輸入輸出格式
輸入格式:
輸入文件equal.in的第一行給出的是題幹中的表達式。第二行是一個整數n(2 <= n <= 26),表示選項的個數。後面n行,每行包括一個選項中的表達式。這n個選項的標號分別是A,B,C,D……
輸入中的表達式的長度都不超過50個字符,而且保證選項中總有表達式和題幹中的表達式是等價的。
輸出格式:
輸出文件equal.out包括一行,這一行包括一系列選項的標號,表示哪些選項是和題幹中的表達式等價的。選項的標號按照字母順序排列,而且之間沒有空格。
輸入輸出樣例
輸入樣例#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年提高組第四題
/* 給a 隨機幾個值,都可以的話等價的概率大一些 註意隨時取模,別乘爆了。 其他就是棧模擬中綴表達式,挺惡心的。 讀入都有坑,還要判斷括號是否匹配。 */ #include<iostream> #include<cstdio> #include<cstring> #include<stack> #define ll long long #define mod 1000007 using namespace std; ll pri[7777]; stack <ll> num,ope; string map[77],str; ll n,ans[777],len,i,j,k; char c; inline void read() { c=getchar(); while(c==‘\n‘ || c==‘\r‘) c=getchar(); while(c!=‘\n‘ && c!=‘\r‘){if(c!=‘ ‘) map[0]+=c;c=getchar();} scanf("%lld",&n); for(i=1;i<=n;i++) { while(c==‘\n‘ || c==‘\r‘) c=getchar(); while(c!=‘\n‘ && c!=‘\r‘){if(c!=‘ ‘)map[i]+=c;c=getchar();} } } inline ll ksm(ll x,ll y) { if(y==1) return x; ll k=ksm(x,y/2); if(y & 1) return (k*k*x)%mod; return (k*k)%mod; } void solve() { for(k=1;k<=10;k++) { while(!num.empty()) num.pop(); while(!ope.empty()) ope.pop(); for(i=0;i<=len;i++) { if(str[i]==‘a‘) num.push(k); else if(str[i]>=‘0‘ && str[i]<=‘9‘) { ll tmp=0; while(str[i]>=‘0‘ && str[i]<=‘9‘) tmp=tmp*10+str[i]-‘0‘,i++; num.push(tmp); i--; } else if(str[i]==‘)‘) { bool flag=1; if(ope.empty()) break; while(ope.top()!=(ll)‘(‘) { c=ope.top();ope.pop(); ll num1=num.top();num.pop(); ll num2=num.top();num.pop(); if(c==‘*‘) num.push((num2*num1)%mod); if(c==‘+‘) num.push((num2+num1)%mod); if(c==‘-‘) num.push((num2-num1)%mod); if(c==‘^‘) num.push(ksm(num2,num1)); if(ope.empty()) break; } if(ope.empty()) break; ope.pop(); } else if(ope.empty()) ope.push(str[i]); else if(str[i]==‘(‘) ope.push(str[i]); else { c=ope.top(); if(c==‘(‘) { ope.push(str[i]); continue; } while(1) { if(ope.empty()) break; c=ope.top(); if(pri[c]<pri[str[i]] || c==‘(‘) break; ope.pop(); ll num1=num.top();num.pop(); ll num2=num.top();num.pop(); if(c==‘*‘) num.push((num2*num1)%mod); if(c==‘+‘) num.push((num2+num1)%mod); if(c==‘-‘) num.push((num2-num1)%mod); if(c==‘^‘) num.push(ksm(num2,num1)); } ope.push(str[i]); } } while(!ope.empty()) { while(1) { if(ope.empty()) break; c=ope.top(); if(c!=‘)‘) break; ope.pop(); if(c==‘)‘ && ope.top()==‘(‘) ope.pop(); else break; } if(ope.empty() || num.size()==1) break; ll num1=num.top();num.pop(); ll num2=num.top();num.pop(); c=ope.top();ope.pop(); if(c==‘*‘) num.push((num2*num1)%mod); if(c==‘+‘) num.push((num2+num1)%mod); if(c==‘-‘) num.push((num2-num1)%mod); if(c==‘^‘) num.push( ksm(num2,num1)); } int otk=num.top(); while(otk<0) otk+=mod; if(j && ans[k]!=otk) break; if(j==0) { ans[k]=num.top(); while(ans[k]<0) ans[k]+=mod; } } } int main() { pri[‘(‘]=pri[‘)‘]=4;pri[‘^‘]=3; pri[‘*‘]=2;pri[‘+‘]=pri[‘-‘]=1; read(); for(j=0;j<=n;j++) { str=map[j]; len=str.size()-1; solve(); if(j && k==11) printf("%c",j+‘A‘-1); } printf("\n"); return 0; }
等價表達式 2005年NOIP全國聯賽提高組(棧模擬)