【NOIP 2005】 等价表达式 题解
昨天复习了一下表达式(栈)和图论相关的算法,结果卡在一道题上,上午做的等价表达式,下午才有所进展,最后好不容易写出来了个像样的程序,,但又因为落谷和codevs上数据有误(左右括号不匹配导致R RE,例如(a+2)^2)),,折腾半天,最后到vijos上也只是分多了点,,也没A掉。
两个栈是肯定的,一个用来存储数字,一个用来存储符号。
读入数字时,直接压入数字栈就可以了,没必要处理,
读入符号时:
1.如果是运算符,当前栈顶的运算符优先级大于等于新运算符,则将栈顶运算符弹出,并将当前数字栈顶的两个数进行相应运算,弹出旧数,压入新结果。不停循环,直到栈里面没有符号或符号优先级低于当前新运算符。
2.如果是“(”,直接压入栈。
3.如果是“)”,不需要压入栈,而是依次将栈里面的符号弹出,并计算。直到遇到一个”(“,然后将”(“也弹出(很关键,否则就会出现运算符数量大于等于数字的情况)。
那怎么知道符号栈的符号和哪两个数字对应呢,需不需要再开一个数组来记录?其实是不需要的,因为题目中不可能出现两个运算符连在一起的情况,即不会出现4+*3这种情况,即使是“(”或“)”和运算符连在一起,因为我们每遇到一个“)”就会弹出栈顶元素直至遇到“(”所以不必担心在弹出的过程中出现运算符大于等于数字的。
具体实现见如下代码
/*
My convictions will not falter.--Poppy
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#define N 32767
using namespace std;
const int test[]={0,2,3,5,7,11,13,41,121,421,4211};
long long sum1,sum2,sum3,n,i,ans1,ans2,ans3;
long long num[1005];
char s[1005];
char ss[1005];
int high(char c)
{
if(c=='+') return 1;
if(c=='-') return 1;
if(c=='*') return 2;
if(c=='^') return 3;
if(c=='(') return 0;
}
long long qmod(int x,int m,int k)
{
long long a=1;
x%=k;
while(m)
{
if(m%2) a=(a*x)%k;
x=x*x%k;
m/=2;
}
return a%k;
}
long long work(int p1,int p2,int p3)
{
if(s[p3]=='+')
return (num[p1]+num[p2])%N;
if(s[p3]=='-')
return (num[p2]-num[p1]+N)%N;//这地方一定要写成(……+N)%N,因为别的运算都加了
//这里如果不加的话,a取23,N取32767时,(a^4)%N-(3*(a^3)%N)%N是个负数,(a^4)%N=17705,而(3*(a^3)%N)%N是24334,相减会变成负数..
//但实际上应该是a^4>3*a^3,用别的等价表达式可能算出来就是正数,然而这个点我以为是选取的N和a有关,盲目的提交了不下20遍....
if(s[p3]=='*')
return (num[p1]*num[p2])%N;
if(s[p3]=='^')
return qmod(num[p2],num[p1],N);
}
int getin(int su)
{
int t=-1;
int total,t1=0,t2=1;
int p=1;
s[1]='(';
char c=' ';
while(c!='\0'&&c!=-1)
{
c=ss[++t];
if(c!=' ')
{
if(c>=48&&c<=57)
{
if(p) t1++,num[t1]=0;
num[t1]=(num[t1]*10+c-48)%N;
p=0;
}
else if(c=='a')
num[++t1]=su,p=1;
else if(c=='(')
s[++t2]='(',p=1;
else if(c==')'||c=='\0'||c==-1)
{
p=1;
while(s[t2]!='('&&s[t2]!='\0'){
num[t1-1]=work(t1,t1-1,t2);
num[t1]=0;
t1--;t2--;
}
t2--;
}
else
{
while((high(c)<=high(s[t2])))
{
num[t1-1]=work(t1,t1-1,t2);
num[t1]=0;
t1--;t2--;
}
s[++t2]=c;
p=1;
}
}
}
return num[1]%N;
}
int read()
{
char c=getchar();
int x=0;
while(c<48||c>57)
c=getchar();
while(c>=48&&c<=57)
x=x*10+c-48,c=getchar();
return x;
}
int main()
{
// freopen("equal.in","r",stdin);
// freopen("equal.out","w",stdout);
gets(ss);
sum2=getin(23);
n=read();
for(i=1;i<=n;i++)
{
memset(s,'\0',sizeof(s));
gets(ss);
ans2=getin(23);
if(ans2==sum2)
printf("%c",i+64);
}
return 0;
}