P1054 等价表达式

题目描述

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

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

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

1. 表达式只可能包含一个变量‘a’。 2. 表达式中出现的数都是正整数,而且都小于10000。 3. 表达式中可以包括四种运算‘+’(加),‘-’(减),‘’(乘),‘^’(乘幂),以及小括号‘(’,‘)’。小括号的优先级最高,其次是‘^’,然后是‘’,最后是‘+’和‘-’。‘+’和‘-’的优先级是相同的。相同优先级的运算从左到右进行。(注意:运算符‘+’,‘-’,‘*’,‘^’以及小括号‘(’,‘)’都是英文字符) 4. 幂指数只可能是1到10之间的正整数(包括1和10)。 5. 表达式内部,头部或者尾部都可能有一些多余的空格。

下面是一些合理的表达式的例子:

((a^1) ^ 2)^3,aa+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个字符,而且保证选项中总有表达式和题干中的表达式是等价的。

输出格式:

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


写完这道题我真想吐血十升。。。

写完这道题我真想吐血十升。。。

写完这道题我真想吐血十升。。。


两个点:

  1. 完美算法不好写,提供一些质数作为a的值代入计算即可
  2. 中缀表达式转后(前)缀表达式。

  • 中缀表达式转后缀表达式

栈s1存数字或运算符,s2存运算符

从左至右扫描

数字进s1

运算符讨论

若s2栈顶优先级小于进来的,我们认为是合法的(想想为什么等于不行)

否则弹出s2到s1直到合法

括号要多一些判断


非完美算法的细节:

  1. 为了避免爆ll,要mod一个大质数。

质数不能太大,不然依旧会爆

也不能太小,不然负数模会出问题

(幸运数字1000000007)

不能每一步都膜,会很慢

  1. a的取值要小,否则很可能要出问题

  2. a的数量不能多不能少,否则很可能会出问题


总结:非完美算法要在看脸的基础上,多想想


code:

// luogu-judger-enable-o2
#include <cstdio>
#include <cstring>
#include <stack>
#define ll long long
using namespace std;
int n;
ll last[15],now[15];
int is[260];
ll pre[5]={5,7,11,2,3};
ll mod=1000000007;
char C[60];
void init()
{
    for(int i='0';i<='9';i++)
        is[i]=1;
    is[int('(')]=2;
    is[int('+')]=3;
    is[int('-')]=3;
    is[int('*')]=4;
    is[int('^')]=5;
    is[int(')')]=6;
    is[int('a')]=7;
}
int cnt;
void read()
{
    char c=getchar();
    while(!is[c]) c=getchar();
    cnt=-1;
    while(c!='\r')
    {
        if(is[c])
            C[++cnt]=c;
        c=getchar();
    }
}

struct node
{
    int k;//符号1还是数字0
    ll c;//数学或者AS码
    node(){}
    node(int k,ll c)
    {
        this->k=k;
        this->c=c;
    }
};

ll get_pow(ll n1,ll n2)
{
    ll nn=1;
    while(n2)
    {
        nn=nn*n1;
        if(nn>=mod)
            nn%=mod;
        n2--;
    }
    return nn;
}

stack <node > s1,s2;

bool get(char *now,int cnt,int flag)
{
    while(!s1.empty()) s1.pop();
    while(!s2.empty()) s2.pop();
    for(int k=0;k<=4;k++)
    {
        for(int i=0;i<=cnt;i++)
        {
            ll x=0;
            char c=*(now+i);
            if(is[c]==1)
            {
                while(is[c]==1&&i<=cnt) {x=x*10+c-'0';i++;c=*(now+i);}
                node tt(0,x);
                s1.push(tt);
                i--;
            }
            else if(is[c]==7)
            {
                node tt(0,pre[k]);
                s1.push(tt);
            }
            else if(is[c]==6)
            {
                while(!s2.empty())
                {
                    if(s2.top().k&&is[s2.top().c]==2)
                        break;
                    s1.push(s2.top());
                    s2.pop();
                }
                if(s2.empty())
                    return false;
                else
                    s2.pop();
            }
            else
            {
                node tt(1,c);
                while(!s2.empty()&&is[s2.top().c]>=is[c]&&s2.top().c!='('&&c!='(')
                {
                    s1.push(s2.top());
                    s2.pop();
                }
                s2.push(tt);
            }
        }
        while(!s2.empty())
        {
            if(is[s2.top().c]==2)
                return false;
            s1.push(s2.top());
            s2.pop();
        }
        while(!s1.empty())
        {
            s2.push(s1.top());
            //printf("%d ",s1.top().c);
            s1.pop();
        }
        //printf("\n");
        while(!s2.empty())
        {
            node tt=s2.top();
            s2.pop();
            if(tt.k)
            {
                ll t1=s1.top().c;
                s1.pop();
                ll t2=s1.top().c;
                s1.pop();
                ll t3;
                if(char(tt.c)=='+')
                    t3=t1+t2;
                else if(char(tt.c)=='-')
                    t3=t2-t1;
                else if(is[tt.c]==4)
                {
                    t3=t2*t1;
                    if(t3>=mod)
                        t3%=mod;
                }
                else if(is[tt.c]==5)
                    t3=get_pow(t2,t1);
                tt.c=t3;
                tt.k=0;
                s1.push(tt);
            }
            else
                s1.push(tt);
        }
        int ttt=s1.top().c%mod;
        if(flag)
            last[k]=s1.top().c%mod;
        else if(last[k]!=ttt)
            return false;
        s1.pop();
    }
    return true;
}

int main()
{
    init();
    read();
    get(C,cnt,1);
    char c=getchar();
    n=0;
    while(!is[c]) c=getchar();
    while(c!='\r') {n=n*10+c-'0';c=getchar();}
    for(int i=0;i<n;i++)
    {
        read();
        if(get(C,cnt,0))
            printf("%c",char(i+'A'));
    }
    return 0;
}

2018.4.29

洛谷 P1054 解题报告的更多相关文章

  1. 洛谷 P1462 解题报告

    P1462 通往奥格瑞玛的道路 题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡 ...

  2. 洛谷 P1879 解题报告

    P1879 [USACO06NOV]玉米田Corn Fields 题目描述 农场主\(John\)新买了一块长方形的新牧场,这块牧场被划分成\(M\)行\(N\)列\((1 ≤ M ≤ 12; 1 ≤ ...

  3. 洛谷 P1069 解题报告

    P1069 细胞分裂 题目描述 \(Hanks\)博士是\(BT\) (\(Bio-Tech\),生物技术) 领域的知名专家.现在,他正在为一个细胞实验做准备工作:培养细胞样本. \(Hanks\) ...

  4. 洛谷 P2491 解题报告

    P2491 消防 题目描述 某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000). 这个国家的人对火焰有超越宇宙的热情,所以这个 ...

  5. 洛谷 P2587 解题报告

    P2587 [ZJOI2008]泡泡堂 题目描述 第XXXX届NOI期间,为了加强各省选手之间的交流,组委会决定组织一场省际电子竞技大赛,每一个省的代表队由n名选手组成,比赛的项目是老少咸宜的网络游戏 ...

  6. 洛谷 P1053 解题报告

    P1053 篝火晚会 题目描述 佳佳刚进高中,在军训的时候,由于佳佳吃苦耐劳,很快得到了教官的赏识,成为了"小教官".在军训结束的那天晚上,佳佳被命令组织同学们进行篝火晚会.一共有 ...

  7. 洛谷 P1057 解题报告

    P1057 传球游戏 题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏. 游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹 ...

  8. 洛谷 P1430 解题报告

    P1430 序列取数 题目描述 给定一个长为\(n\)的整数序列\((n<=1000)\),由\(A\)和\(B\)轮流取数(\(A\)先取).每个人可从序列的左端或右端取若干个数(至少一个), ...

  9. 洛谷 P1613 解题报告

    P1613 跑路 题目描述 小\(A\)的工作不仅繁琐,更有苛刻的规定,要求小\(A\)每天早上在\(6:00\)之前到达公司,否则这个月工资清零.可是小\(A\)偏偏又有赖床的坏毛病.于是为了保住自 ...

随机推荐

  1. python调用数据库并查询

    http://blog.csdn.net/pipisorry/article/details/48024795 python调用数据库命令 conn = sqlite3.connect(". ...

  2. HashMap与HashTable面试宝典

    u012233832的专栏 初生牛犊 目录视图 摘要视图 订阅 写博客,送money.送书.送C币啦   7-8月博乐推荐文章    砸BUG 得大奖 100%中奖率   微信开发学习路线高级篇上线  ...

  3. Android 利用WebViewJavascriptBridge 实现js和java的交互(一)

    此文出自:http://blog.csdn.net/sk719887916/article/details/47189607,skay 按安卓开发目前现状来说,开发者大部分时间还是花在UI的屏幕适配上 ...

  4. ViewPager适配器学习记录( pageAdapter和FragmentPagerAdapter/FragmentStatePagerAdapter))

    1.概述 ViewPager,顾名思义实现控件的滚动功能,是Support-v4的包中类,使用前要先导包.使用的时候跟listView有点相似,需要设置对应的适配器,通常有俩大类 [pageAdapt ...

  5. 原生CSS动画回调事件

    原文链接: Detecting CSS Animation Completion with JavaScript 原文日期: 2014年02月20日 翻译日期: 2014年02月21日 翻译人员: 铁 ...

  6. android 线程那点事

    在操作系统中,线程是操作系统调度的最小单元,同时线程又是一种受限的系统资源,即线程不可能无限制的产生,并且线程的创建和销毁都会有相应的开销,当系统中存在大量的线程时,系统会通过时间片轮转的方式调度每个 ...

  7. 中文注释 MariaDB my.cnf 大型服务器配置模板

    文件如下所示,请根据需要进行修改: 翻译日期: 2014年5月22日 翻译人员: 铁锚 # /usr/share/mysql/my-huge.cnf # MariaDB 配置文件 示例模板(huge, ...

  8. TCP的核心系列 — 重传队列的更新和时延的采样(一)

    重传队列实际上就是发送队列(sk->sk_write_queue),保存着发送且未确认的数据段. 当有新的数据段被确认时,需要把这些段从重传队列中删除,同时更新一些变量,包括 packets_o ...

  9. Python 3.7 将引入 dataclass 装饰器

    简评:Python 3.7 将于今年夏天发布,Python 3.7 中将会有许多新东西,最激动人心的新功能之一是 dataclass 装饰器. 什么是 Data Class 大多数 Python 开发 ...

  10. golang 常见疑惑总结

    经常会有一些朋友问go语言的一些问题和疑惑,其实好多问题在官方文档和stackoverflow里都有详细的讲解,只要你肯花时间读一遍官方文档和Effective Go基本上都有找到答案.本文总结一下大 ...