1107 等价表达式
2005年NOIP全国联赛提高组
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 钻石 Diamond
查看运行结果
题目描述 Description
明明进了中学之后,学到了代数表达式。有一天,他碰到一个很麻烦的选择题。这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的。
这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题。假设你是明明,能完成这个任务吗?
这个选择题中的每个表达式都满足下面的性质:
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……
输入描述 Input Description
输入第一行给出的是题干中的表达式。第二行是一个整数n(2<=n<=26),表示选项的个数。后面n行,每行包括一个选项中的表达式。这n个选项的标号分别是A,B,C,D……
输入中的表达式的长度都不超过50个字符,而且保证选项中总有表达式和题干中的表达式是等价的。
输出描述 Output Description
输出包括一行,这一行包括一系列选项的标号,表示哪些选项是和题干中的表达式等价的。选项的标号按照字母顺序排列,而且之间没有空格。
样例输入 Sample Input
(a+1)^2
3
(a-1)^2+4*a
a+1+a
a^2+2*a*1+1^2+10-10+a-a
样例输出 Sample Output
AC
数据范围及提示 Data Size & Hint
【数据规模】
对于30%的数据,表达式中只可能出现两种运算符‘+’和‘-’;
对于其它的数据,四种运算符‘+’,‘-’,‘*’,‘^’在表达式中都可能出现。
对于全部的数据,表达式中都可能出现小括号‘(’和‘)’。
分类标签 Tags 点此展开
题解:
表达式计算
就是压栈处理;
设a为一个质数,模数为另一个质数,然后暴力算多项式的答案,如果答案相等就认为两个多项式相等。
这种hash有出错概率的题为什么还是要用hash呢?因为出错的概率实在太小了,a和模数的值取得好出题人根本没法卡。
(不一定非要取3、4次质数,主要是rp)
注意有空格。
裸的表达式计算
#include<cstdio> #include<cmath> #include<cstring> using namespace std; #define N 256 int num[N],p=1,i,z; char symbol[N],s[N],t[N],ans[N]; inline void push(){ symbol[++p]=s[i]; } inline void pop(){ switch(symbol[p--]){ case ‘^‘:num[p]=pow(num[p],num[p+1]);break; case ‘+‘:num[p]+=num[p+1];break; case ‘-‘:num[p]-=num[p+1];break; case ‘*‘:num[p]*=num[p+1];break; case ‘/‘:num[p]/=num[p+1];break; } } inline bool can(){ if((s[i]==‘+‘||s[i]==‘-‘)&&symbol[p]!=‘(‘) return 1; if(s[i]==‘^‘&&symbol[p]==‘^‘) return 1; if((s[i]==‘*‘||s[i]==‘/‘)&&(symbol[p]==‘*‘||symbol[p]==‘/‘)) return 1; return 0; } inline void deal(){ gets(s); int len=strlen(s); s[len]=‘)‘;symbol[p]=‘(‘; while(i<len){ while(s[i]==‘(‘) push(),i++; int x(0); while(s[i]>=‘0‘&&s[i]<=‘9‘) x=x*10+s[i++]-‘0‘; num[p]=x; do{ if(s[i]==‘)‘){ while(symbol[p]!=‘(‘) pop(); num[--p]=num[p+1]; } else{ while(can()) pop(); push(); } i++; }while(i<len&&s[i-1]==‘)‘); } } int main(){ deal(); printf("%d\n",num[0]); return 0; }
本题AC代码:
#include<cstdio> #include<cstring> using namespace std; #define ll long long const int N=10003; const int a=10007; const int p=100007; char s[N],c[N],sym[N]; int m,num[N],yxj[N],topnum,topch; int get(char ch){ if(ch==‘+‘||ch==‘-‘) return 1; if(ch==‘*‘) return 2; if(ch==‘^‘) return 3; } int ipow(int a,int b){ ll t=1; for(int i=1;i<=b;i++) t=t*a%p; return (int)t; } int cal(char ch,int a,int b){ switch(ch){ case ‘^‘:return ipow(a,b);break; case ‘+‘:return (a+b)%p;break; case ‘-‘:return (a-b+p)%p;break; case ‘*‘:return (int)(1ll*a*b%p);break; } } bool can(char ch){ return (ch==‘+‘||ch==‘-‘||ch==‘*‘||ch==‘^‘||ch==‘(‘||ch==‘)‘); } int deal() { int len=strlen(s),tmp=0,j=100,k; c[0]=‘ ‘; for(int i=0;i<len;++i) if(s[i]!=‘ ‘) c[++tmp]=s[i]; c[tmp+1]=‘ ‘; len=tmp;tmp=1;topnum=topch=0; while(tmp<=len) { if(can(c[tmp])){ if(c[tmp]==‘(‘) j+=10; else if(c[tmp]==‘)‘) j-=10; else{ k=get(c[tmp]); while(topch&&yxj[topch]>=k+j) { num[topnum-1]=cal(sym[topch],num[topnum-1],num[topnum]); --topnum;--topch; } sym[++topch]=c[tmp];yxj[topch]=k+j; } ++tmp; } else{ if(c[tmp]==‘a‘) num[++topnum]=a,++tmp; else{ k=0; for(;c[tmp]>=‘0‘ && c[tmp]<=‘9‘ && tmp<=len;++tmp)k=k * 10+c[tmp]-‘0‘; num[++topnum]=k; } } } while(topch){ num[topnum-1]=cal(sym[topch],num[topnum-1],num[topnum]); --topnum;--topch; } return num[1]; } int main() { gets(s); int res=deal(); scanf("%d\n",&m); for(int i=1;i<=m;++i){ gets(s); int now=deal(); if(now==res) putchar(64+i); } puts(""); return 0; }