NOIP2005 等价表达式
题目描述
明明进了中学之后,学到了代数表达式。有一天,他碰到一个很麻烦的选择题。这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的。 这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题。假设你是明明,能完成这个任务吗?
这个选择题中的每个表达式都满足下面的性质:
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…… 对于30%的数据,表达式中只可能出现两种运算符‘+’和‘-’; 对于其它的数据,四种运算符‘+’,‘-’,‘*’,‘^’在表达式中都可能出现。 对于全部的数据,表达式中都可能出现小括号‘(’和‘)’。
输入
输入的第一行给出的是题干中的表达式。第二行是一个整数n(2 < = n < = 26),表示选项的个数。后面n行,每行包括一个选项中的表达式。这n个选项的标号分别是A,B,C,D…… 输入中的表达式的长度都不超过50个字符,而且保证选项中总有表达式和题干中的表达式是等价的。
输出
输出包括一行,这一行包括一系列选项的标号,表示哪些选项是和题干中的表达式等价的。选项的标号按照字母顺序排列,而且之间没有空格。
样例输入
样例输出
/* 字符串处理,注意运算符顺序,注意int,long long 不要打反 */ #include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #define ll long long #define fo(i,l,r) for(int i = l;i <= r;i++) #define fd(i,l,r) for(int i = r;i >= l;i--) using namespace std; const int maxn = 2050; char s[30][maxn]; bool vis[30]; ll n,ans1,ans2,sed,mod; ll read(){ ll x=0,f=1; char ch=getchar(); while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}; while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getchar();}; return x*f; } bool is_them(char a,char b,char c){ return (a == b || a== c); } ll q_mul(ll a,ll b,ll p){ ll ret = 0; while(b){ if(b&1) ret = (ret + a) % p; a = (a + a) % p; b>>=1; } return ret; } ll q_pow(ll a,ll b,ll p){ ll ret = 1; while(b){ if(b&1) ret = q_mul(ret,a,p); a = q_mul(a,a,p); b>>=1; } return ret; } ll str2int(char *s,int l,int r){ if(l==r&&s[l]=='a'){ return sed; } ll n = 0; for(int i=l;i<=r;i++){ if(s[i]>='0'&&s[i]<='9') n=(n*10+(s[i]-'0'))%mod; else if(s[i]!=' ') break; } return n; } ll calc(char *exp,int l,int r){ int lv=0,p=-1; while(exp[l]==' '&&l<=r) l++; while(exp[r]==' '&&l<=r) r--; for(int i=l;i<=r;i++){ char &c = exp[i]; if(c==' ')continue; if(c=='(')lv++; if(c==')')lv--; if(lv==0){ if(is_them(c,'+','-')) p=i; else if(is_them(c,'*','/') && (p==-1||!is_them(exp[p],'+','-'))) p=i; else if(c=='^' && (p==-1 || exp[p] == '^')){ p=i; } } } if(lv < 0 && exp[r] == ')') return calc(exp,l,r-1); else if(lv > 0 && exp[r] == '(') return calc(exp,l+1,r); if(p==-1){ if(exp[l]=='('&&exp[r]==')') return calc(exp,l+1,r-1); if(exp[l]=='(') return calc(exp,l+1,r); if(exp[r]==')') return calc(exp,l,r-1); return str2int(exp,l,r); }else{ ll a=calc(exp,l,p-1); ll b=calc(exp,p+1,r); switch(exp[p]){ case'+':return (a+b)%mod; case'-':return (a-b+mod)%mod; case'*':return (a*b)%mod; case'/':return a/b; case'^':return q_pow(a,b,mod); }; } return 0; } bool tst(int id){ bool ok = false; for(int i = 1;i <= strlen(s[id]+1);i++){ if(s[id][i] != ' ') ok = true; } return ok; } int main(){ cin.getline(s[0]+1,55,'\n'); cin>>n; for(int i = 1;i <= n;i++){ cin.getline(s[i]+1,55,'\n'); while(!tst(i))cin.getline(s[i]+1,55,'\n'); } sed = 6; mod = 70177; ans1 = calc(s[0],1,strlen(s[0]+1)); for(int i = 1;i <= n;i++){ ans2 = calc(s[i],1,strlen(s[i]+1)); if(ans2 == ans1) vis[i] = true; } sed = 131; mod = 92311; ans1 = calc(s[0],1,strlen(s[0]+1)); for(int i = 1;i <= n;i++){ ans2 = calc(s[i],1,strlen(s[i]+1)); if(ans2 == ans1) vis[i] = true; } for(int i = 1;i <= n;i++){ char now = 'A'+i-1; if(vis[i]) cout<<now; } return 0; }