codevs 1107 等价表达式
2005年NOIP全国联赛提高组
明明进了中学之后,学到了代数表达式。有一天,他碰到一个很麻烦的选择题。这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的。
这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题。假设你是明明,能完成这个任务吗?
这个选择题中的每个表达式都满足下面的性质:
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%的数据,表达式中只可能出现两种运算符‘+’和‘-’;
对于其它的数据,四种运算符‘+’,‘-’,‘*’,‘^’在表达式中都可能出现。
对于全部的数据,表达式中都可能出现小括号‘(’和‘)’。
1 /* 2 机智的方法:给a代入特殊值。不要代入0,1,-1这样的数。最好代质数。 3 只代入一个数还是很有可能出现两个不等的式子算出来结果相等。 4 多代几个数 5 还有一个问题,代数的话,计算结果可能会超过long long范围。 6 计算的时候记得模一个大质数 7 因为我们取了若干个数代进去,所以即使模了一个数冲突的几率也很小 8 下面进入正题:如何计算表达式的值? 9 我们需要开两个栈:一个用来存储数字,一个用来存储符号。 10 读入数字时,压入数字栈 11 读入符号时: 12 1.如果是运算符,当前栈顶的运算符优先级大于等于新运算符,则将栈顶运算符弹出,并将当前数字栈顶的两个数进行相应运算,弹出旧数,压入新结果。不停循环,直到栈里面没有符号或符号优先级低于当前新运算符。 13 2.如果是(,直接压入栈。 14 3.如果是),则依次将栈里面的符号弹出,并计算。直到遇到一个(。 15 16 */ 17 #include<cstring> 18 #include<iostream> 19 using namespace std; 20 #include<cstdio> 21 #define mod 32767 22 #define max_len 10 23 #define L 55 24 char s[L],b[L],n; 25 int ans[max_len+5]; 26 int sumstack[L],fhstack[L]; 27 int len1=0,len2=0; 28 int quick_mod(int x,int y)//x^y 29 { 30 int ret=1; 31 while(y) 32 { 33 if(y&1) 34 { 35 ret*=x; 36 ret%=mod; 37 } 38 y>>=1;x*=x; 39 x%=mod; 40 } 41 return ret; 42 } 43 void multi() 44 { 45 switch(fhstack[len2]) 46 { 47 case 1:sumstack[len1-1]+=sumstack[len1]; 48 sumstack[len1-1]%=mod; 49 break; 50 case 2:sumstack[len1-1]-=sumstack[len1]; 51 sumstack[len1-1]%=mod; 52 break; 53 case 3:sumstack[len1-1]*=sumstack[len1]; 54 sumstack[len1-1]%=mod; 55 break; 56 case 4:sumstack[len1-1]=quick_mod(sumstack[len1-1],sumstack[len1]); 57 sumstack[len1-1]%=mod; 58 break; 59 case 5:len2--; return;/*遇到左括号,直接跳过,是符号栈指针--*/ 60 } 61 len1--;len2--; 62 } 63 int js(char s1[],int k) 64 { 65 memset(sumstack,0,sizeof(sumstack)); 66 memset(fhstack,0,sizeof(fhstack)); 67 sumstack[1]=0;len1=1; 68 len2=0; 69 int len=strlen(s1); 70 for(int i=0;i<len;++i) 71 { 72 if(s1[i]==' ') continue; 73 if(s1[i]=='a') 74 { 75 sumstack[++len1]=k; 76 continue; 77 } 78 if(s1[i]>='0'&&s1[i]<='9') 79 { 80 sumstack[++len1]=s1[i]-'0'; 81 while(s1[i+1]>='0'&&s1[i+1]<='9') 82 { 83 sumstack[len1]=sumstack[len1]*10+s1[i+1]-'0'; 84 sumstack[len1]%=mod; 85 i++; 86 } 87 continue; 88 } 89 switch(s1[i]) 90 { 91 case '(': fhstack[++len2]=5;break; 92 case '+':while(len2>0&&fhstack[len2]>0&&fhstack[len2]<5) multi(); 93 fhstack[++len2]=1; 94 break; 95 /*注意这里的是while,不是if,就是如果满足条件的话,就把前面的一直算*/ 96 case '-':while(len2>0&&fhstack[len2]>0&&fhstack[len2]<5) multi(); 97 fhstack[++len2]=2; 98 break; 99 case '*':while(len2>0&&fhstack[len2]>2&&fhstack[len2]<5) multi(); 100 fhstack[++len2]=3; 101 break; 102 case '^':while(len2>0&&fhstack[len2]>3&&fhstack[len2]<5) multi(); 103 fhstack[++len2]=4; 104 break; 105 case ')':while(len2>0&&fhstack[len2]<5) multi(); 106 if(fhstack[len2]==5) len2--; 107 break; 108 } 109 } 110 while(len2) multi(); 111 if(len1==1) return (sumstack[1]+mod)%mod; 112 return (sumstack[2]+mod)%mod; 113 } 114 int main() 115 { 116 gets(s); 117 for(int i=1;i<max_len;++i) 118 ans[i]=js(s,i); 119 scanf("%d ",&n); 120 for(int i=1;i<=n;++i) 121 { 122 gets(b); 123 bool flag=true; 124 for(int i=1;i<max_len;++i) 125 { 126 int x=js(b,i); 127 if(x!=ans[i]) 128 { 129 flag=false; 130 break; 131 } 132 } 133 if(flag) 134 printf("%c",'A'-1+i); 135 } 136 return 0; 137 }