洛谷 P1054 等价表达式
题目描述
明明进了中学之后,学到了代数表达式。有一天,他碰到一个很麻烦的选择题。这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的。
这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题。假设你是明明,能完成这个任务吗?
这个选择题中的每个表达式都满足下面的性质:
- 表达式只可能包含一个变量‘ aa ’。
- 表达式中出现的数都是正整数,而且都小于 1000010000 。
- 表达式中可以包括四种运算
+
(加),-
(减),*
(乘),^
(乘幂),以及小括号(
,)
。小括号的优先级最高,其次是^
,然后是*
,最后是+
和-
。+
和-
的优先级是相同的。相同优先级的运算从左到右进行。(注意:运算符+
,-
,*
,^
以及小括号(
,)
都是英文字符) - 幂指数只可能是 11 到 1010 之间的正整数(包括 11 和 1010 )。
- 表达式内部,头部或者尾部都可能有一些多余的空格。
下面是一些合理的表达式的例子:
((a^1) ^ 2)^3
,a*a+a-a
,((a+a))
,9999+(a-a)*a
,1 + (a -1)^3
,1^10^9
………
输入输出格式
输入格式:
第一行给出的是题干中的表达式。
第二行是一个整数 n(2 \le n \le 26)n(2≤n≤26) ,表示选项的个数。后面 nn 行,每行包括一个选项中的表达式。这 nn 个选项的标号分别是 A,B,C,D…A,B,C,D…
输入中的表达式的长度都不超过50个字符,而且保证选项中总有表达式和题干中的表达式是等价的。
输出格式:
一行,包括一系列选项的标号,表示哪些选项是和题干中的表达式等价的。选项的标号按照字母顺序排列,而且之间没有空格。
输入输出样例
说明
对于30%的数据,表达式中只可能出现两种运算符‘+’和-
;
对于其它的数据,四种运算符+
,-
,*
,^
在表达式中都可能出现。
对于全部的数据,表达式中都可能出现小括号(
和)
。
思路:模拟
有很多细节问题需要注意,尤其像括号不匹配等问题,虽然仅是个模拟,但是很麻烦
#include<cstring> #include<cstdlib> #include<cstdio> #include<cctype> #include<ctime> #define maxn 50 #define max_len 10 using namespace std; int mod; int x[max_len], p[maxn+20], q[maxn+20]; char a[maxn+20], b[maxn+20]; int power(int i, int j) { int ans = 1; while(j > 0) { if(j & 1) ans = (ans * i) % mod; i = (i * i) % mod, j >>= 1; } return ans; } void work() { switch(p[p[0]]) { case 1: q[q[0]-1] += q[q[0]]; q[q[0]-1] %= mod; break; case 2: q[q[0]-1] -= q[q[0]]; q[q[0]-1] %= mod; break; case 3: q[q[0]-1] *= q[q[0]]; q[q[0]-1] %= mod; break; case 4: q[q[0]-1] = power(q[q[0]-1], q[q[0]]); break; case 5: p[0]--; return; case 6: p[0]--; return; } p[0]--, q[0]--; } int get(char s[], int x) { int i, j, k, len = strlen(s); p[0] = 0, q[0] = 1, q[1] = 0; for(i = 0; i < len; i++) { if(s[i] == ' ') continue; if(s[i] == 'a') { q[++q[0]] = x; continue; } if(isdigit(s[i])) { q[++q[0]] = s[i]-'0'; while(isdigit(s[i+1])) q[q[0]] = (q[q[0]]*10 + s[++i]-'0') % mod; continue; } switch(s[i]) { case '(': p[++p[0]] = 5; break; case '+': while(p[0]>0 && p[p[0]]>0 && p[p[0]]<5) work(); p[++p[0]] = 1; break; case '-': while(p[0]>0 && p[p[0]]>0 && p[p[0]]<5) work(); p[++p[0]] = 2; break; case '*': while(p[0]>0 && p[p[0]]>2 && p[p[0]]<5) work(); p[++p[0]] = 3; break; case '^': while(p[0]>0 && p[p[0]]>3 && p[p[0]]<5) work(); p[++p[0]] = 4; break; case ')': while(p[0]>0 && p[p[0]]<5) work(); if(p[p[0]] == 5) p[0]--; break; } } while(p[0]) work(); if(q[0] == 1) return (q[1] + mod) % mod; return (q[2] + mod) % mod; } int main() { srand(time(0)); mod = rand() % 10000 + 100; int i, j, k, n; gets(a); for(i = 1; i < max_len; i++) x[i] = get(a, i); scanf("%d\n", &n); for(i = 0; i < n; i++) { gets(b); for(j = 1; j < max_len; j++) if(get(b, j) != x[j]) break; if(j >= max_len) printf("%c", 'A'+i); } return 0; }