明明進了中學之後,學到了代數表達式。有一天,他碰到一個很麻煩的選擇題。這個題目的題幹中首先給出了一個代數表達式,然後列出了若干選項,每個選項也是一個代數表達式,題目的要求是判斷選項中哪些代數表達式是和題幹中的表達式等價的。
這個題目手算很麻煩,因爲明明對計算機編程很感興趣,所以他想是不是可以用計算機來解決這個問題。假設你是明明,能完成這個任務嗎?
這個選擇題中的每個表達式都滿足下面的性質:
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……
輸入第一行給出的是題幹中的表達式。第二行是一個整數n(2<=n<=26),表示選項的個數。後面n行,每行包括一個選項中的表達式。這n個選項的標號分別是A,B,C,D……
輸入中的表達式的長度都不超過50個字符,而且保證選項中總有表達式和題幹中的表達式是等價的。
輸出包括一行,這一行包括一系列選項的標號,表示哪些選項是和題幹中的表達式等價的。選項的標號按照字母順序排列,而且之間沒有空格。
(a+1)^2
3
(a-1)^2+4*a
a+1+a
a^2+2*a*1+1^2+10-10+a-a
AC
【數據規模】
對於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>