等价表达式 2005年NOIP全国联赛提高组(栈模拟)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了等价表达式 2005年NOIP全国联赛提高组(栈模拟)相关的知识,希望对你有一定的参考价值。

P1054 等价表达式

题目描述

明明进了中学之后,学到了代数表达式。有一天,他碰到一个很麻烦的选择题。这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和题干中的表达式等价的。

这个题目手算很麻烦,因为明明对计算机编程很感兴趣,所以他想是不是可以用计算机来解决这个问题。假设你是明明,能完成这个任务吗?

这个选择题中的每个表达式都满足下面的性质:

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……

输入输出格式

输入格式:

 

输入文件equal.in的第一行给出的是题干中的表达式。第二行是一个整数n(2 <= n <= 26),表示选项的个数。后面n行,每行包括一个选项中的表达式。这n个选项的标号分别是A,B,C,D……

输入中的表达式的长度都不超过50个字符,而且保证选项中总有表达式和题干中的表达式是等价的。

 

输出格式:

 

输出文件equal.out包括一行,这一行包括一系列选项的标号,表示哪些选项是和题干中的表达式等价的。选项的标号按照字母顺序排列,而且之间没有空格。

 

输入输出样例

输入样例#1:
( a + 1) ^2
3
(a-1)^2+4*a
a + 1+ a
a^2 + 2 * a * 1 + 1^2 + 10 -10 +a -a
输出样例#1:
AC

说明

对于30%的数据,表达式中只可能出现两种运算符‘+’和‘-’;

对于其它的数据,四种运算符‘+’,‘-’,‘*’,‘^’在表达式中都可能出现。

对于全部的数据,表达式中都可能出现小括号‘(’和‘)’。

2005年提高组第四题

 

/*
给a 随机几个值,都可以的话等价的概率大一些
注意随时取模,别乘爆了。
其他就是栈模拟中缀表达式,挺恶心的。
读入都有坑,还要判断括号是否匹配。 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>

#define ll long long
#define mod 1000007

using namespace std;

ll pri[7777];
stack <ll> num,ope;
string map[77],str;
ll n,ans[777],len,i,j,k;
char c;

inline void read()
{
    c=getchar();
    while(c==\n || c==\r) c=getchar();
    while(c!=\n && c!=\r){if(c!= ) map[0]+=c;c=getchar();}
    scanf("%lld",&n);
    for(i=1;i<=n;i++)
    {
        while(c==\n || c==\r) c=getchar();
        while(c!=\n && c!=\r){if(c!= )map[i]+=c;c=getchar();}
    }
}

inline ll ksm(ll x,ll y)
{
    if(y==1) return x;
    ll k=ksm(x,y/2);
    if(y & 1) return (k*k*x)%mod;
    return (k*k)%mod;
}

void solve()
{
        for(k=1;k<=10;k++)
        {
            while(!num.empty()) num.pop();
            while(!ope.empty()) ope.pop();
            for(i=0;i<=len;i++)
            {
                if(str[i]==a) num.push(k);
                else if(str[i]>=0 && str[i]<=9)
                {
                    ll tmp=0;
                    while(str[i]>=0 && str[i]<=9)
                        tmp=tmp*10+str[i]-0,i++;
                    num.push(tmp);
                    i--;
                }
                else if(str[i]==))
                {
                    bool flag=1;
                    if(ope.empty()) break;
                    while(ope.top()!=(ll)()
                    {
                        c=ope.top();ope.pop();
                        ll num1=num.top();num.pop();
                        ll num2=num.top();num.pop();
                        if(c==*) num.push((num2*num1)%mod);
                        if(c==+) num.push((num2+num1)%mod);
                        if(c==-) num.push((num2-num1)%mod);
                        if(c==^) num.push(ksm(num2,num1));
                        if(ope.empty()) break;
                    }
                    if(ope.empty()) break;
                    ope.pop();
                }
                else if(ope.empty()) ope.push(str[i]);
                else if(str[i]==() ope.push(str[i]);
                else
                {
                    c=ope.top();
                    if(c==()
                    {
                        ope.push(str[i]);
                        continue;
                    }
                    while(1)
                    {
                        if(ope.empty()) break;
                        c=ope.top();
                        if(pri[c]<pri[str[i]] || c==() break;
                        ope.pop();
                        ll num1=num.top();num.pop();
                        ll num2=num.top();num.pop();
                        if(c==*) num.push((num2*num1)%mod);
                        if(c==+) num.push((num2+num1)%mod);
                        if(c==-) num.push((num2-num1)%mod);
                        if(c==^) num.push(ksm(num2,num1));
                    }
                    ope.push(str[i]);
                }
            }
            while(!ope.empty())
            {
                while(1)
                {
                    if(ope.empty()) break;
                    c=ope.top();
                    if(c!=)) break;
                    ope.pop();
                    if(c==) && ope.top()==() ope.pop();
                    else break;
                }
                if(ope.empty() || num.size()==1) break;
                ll num1=num.top();num.pop();
                ll num2=num.top();num.pop();
                c=ope.top();ope.pop();
                if(c==*) num.push((num2*num1)%mod);
                if(c==+) num.push((num2+num1)%mod);
                if(c==-) num.push((num2-num1)%mod);
                if(c==^) num.push( ksm(num2,num1));
            }
            int otk=num.top();
            while(otk<0) otk+=mod;
            if(j && ans[k]!=otk) break;
            if(j==0)
            {
                ans[k]=num.top();
                while(ans[k]<0) ans[k]+=mod;
            }
        }
}

int main()
{
    pri[(]=pri[)]=4;pri[^]=3;
    pri[*]=2;pri[+]=pri[-]=1;
    read();
    for(j=0;j<=n;j++)
    {
        str=map[j];
        len=str.size()-1;
        solve();
        if(j && k==11) printf("%c",j+A-1);
    }
    printf("\n");
    return 0;
}

 

以上是关于等价表达式 2005年NOIP全国联赛提高组(栈模拟)的主要内容,如果未能解决你的问题,请参考以下文章

1102 采药 2005年NOIP全国联赛普及组

codevs 1102 采药 2005年NOIP全国联赛普及组

旅行家的预算 1999年NOIP全国联赛普及组NOIP全国联赛提高组

1058 合唱队形 2004年NOIP全国联赛提高组

采药 2005年NOIP全国联赛普及组&疯狂的采药

1068 乌龟棋 2010年NOIP全国联赛提高组