zoukankan      html  css  js  c++  java
  • Codeforces 7E

    Codeforces 7E - Defining Macros 题解

    前言

    开始使用博客园了,很想写点东西。(逃

    这是一道Codeforces题目

    做法

    一道大模拟

    相信大家都看得懂题目意思,我就不赘述了。

    首先我们读进来(n)行,对于每一行,我们把它初步分成一下四块内容:

    • #
    • define
    • 宏的名字
    • 宏的表达式

    注意:#define中间可能会有空格,define和宏的名字,宏的名字和宏的表达式之间一定会有空格。

    现在我们来处理一下表达式,把它处理到一个序列内,这个序列包含:(,),+,-,*,/,变量,常量

    对于每一个对象,我们可以如下定义:(优先级值越小越优先)

    • 变量,常量,括号:优先级为(0)
    • /,*:优先级为(1)
    • +,-:优先级为(2)
    • 宏:优先级为内部表达式的优先级

    同时我们可以发现一个表达式,合法时满足以下条件:

    • /要求左侧对象优先级不大于1,右侧对象优先级等于0

    • *要求左侧对象优先级不大于1,右侧对象优先级不大于1

    • -要求右侧对象优先级不大于1

    • 其余对象不做要求

    于是,对于一个表达式(S),我们可以递归地考虑:

    • 空表达式常量变量优先级(0)

    • 优先级为内部表达式优先级,合法也取决于内部表达式是否合法

    • (表达式),优先级为(0),合法取决于内部是否合法

    • 表达式+表达式表达式-表达式,合法取决于+,-的运算,优先级为(2)

    • 表达式/表达式表达式/表达式,合法取决于*,/的运算,优先级为(1)

    好了,成了,可以写代码了!

    程序

    #include<bits/stdc++.h>
    using namespace std;
    
    int n;
    vector<string> expr[105];
    //expr为id对应的处理好的表达式序列
    int prio[105];
    //prio为记忆化处理id对应的表达式的优先级
    map<string,int> def;
    //def为宏名称对应的id
    
    inline bool valid(int lp,char op,int rp){
    //左表达式优先级lp,运算符op,右表达式优先级rp,是否合法
        if(op=='/')return lp<=1&&rp<=0;
        if(op=='*')return lp<=1&&rp<=1;
        if(op=='+')return lp<=2&&rp<=2;
        if(op=='-')return lp<=2&&rp<=1;
        //cerr<<"OP INVALID"<<endl;
        return false;
    }
    
    int dfs(int id);
    
    inline bool isnumber(const string &s){
    //string是否存入数字
        for(int i=0;i<s.size();i++){
            if(s[i]<'0'||s[i]>'9')return false;
        }return true;
    }
    
    inline bool ismacro(const string &s){
    //string是否存入宏
        return def.find(s)!=def.end();
    }
    
    inline bool isvalue(const string &s){
    //string是否存入变量
        for(int i=0;i<s.size();i++){
            if(!isalpha(s[i]))return false;
        }return true;
    }
    
    int parse(const vector<string> &v,int l,int r){
        if(l>=r)return 0;//空表达式
        if(l+1==r){//只有一个单独对象
            if(isnumber(v[l])){//是常量
                return 0;
            }
            if(ismacro(v[l])){//是宏
                return dfs(def[v[l]]);
            }
            if(isvalue(v[l])){//是变量,要在宏后判断
                return 0;
            }
            //cerr<<"PARSING: "<<v[l]<<endl;
            //cerr<<"PARSE INVALID"<<endl;
            return -1;//什么都不是,不可能出现这种情况(除非写错了)
        }
        if(v[l]=="("&&v[r-1]==")"){//被括号包裹
            bool f=true;
            int bkc=0;
            for(int i=l;i<r;i++){//检查括号配对情况
                if(v[i]=="(")bkc++;
                if(v[i]==")")bkc--;
                if(bkc==0&&i+1!=r){
                    f=false;
                    break;
                }
            }
            if(f){
                parse(v,l+1,r-1);
                return 0;
            }
        }
        int bkc=0;
        for(int i=r-1;i>=l;i--){//优先找+、-,此处i从小到大亦可
            if(v[i]==")")bkc++;
            if(v[i]=="(")bkc--;
            if(bkc)continue;//判断是否在括号内
            if(v[i]=="+"){
                if(valid(parse(v,l,i),'+',parse(v,i+1,r))){
                    return 2;
                }else{
                    cout<<"Suspicious"<<endl;
                    exit(0);//不合法直接退出
                }
            }
            if(v[i]=="-"){
                if(valid(parse(v,l,i),'-',parse(v,i+1,r))){
                    return 2;
                }else{
                    cout<<"Suspicious"<<endl;
                    exit(0);//不合法直接退出
                }
            }
        }
        for(int i=r-1;i>=l;i--){//再找*、/,此处i从小到大亦可
            if(v[i]==")")bkc++;
            if(v[i]=="(")bkc--;
            if(bkc)continue;//判断是否在括号内
            if(v[i]=="*"){
                if(valid(parse(v,l,i),'*',parse(v,i+1,r))){
                    return 1;
                }else{
                    cout<<"Suspicious"<<endl;
                    exit(0);//不合法直接退出
                }
            }
            if(v[i]=="/"){
                if(valid(parse(v,l,i),'/',parse(v,i+1,r))){
                    return 1;
                }else{
                    cout<<"Suspicious"<<endl;
                    exit(0);//不合法直接退出
                }
            }
        }
        //cerr<<"PARSING: "<<l<<' '<<r<<endl;
        //cerr<<"PARSE INVALID"<<endl;
        return -1;//不可能出现的情况
    }
    
    int dfs(int id){//记忆化计算id对应的表达式的优先级
        //cerr<<"DFSING IN: "<<id<<endl;cerr<<prio[id]<<endl;
        if(prio[id]!=-1)return prio[id];
        return prio[id]=parse(expr[id],0,expr[id].size());
    }
    
    vector<string> mkexp(const string &s){//处理原始字符串,获得表达式对象的序列
        vector<string> res;
        for(int i=0;i<s.size();i++){
            if(s[i]==' '){
                continue;
            }
            if(s[i]=='('){
                res.push_back("(");
                continue;
            }
            if(s[i]==')'){
                res.push_back(")");
                continue;
            }
            if(s[i]=='+'){
                res.push_back("+");
                continue;
            }
            if(s[i]=='-'){
                res.push_back("-");
                continue;
            }
            if(s[i]=='*'){
                res.push_back("*");
                continue;
            }
            if(s[i]=='/'){
                res.push_back("/");
                continue;
            }
            string tmp;
            int j;
            for(j=i;j<s.size()&&(isalpha(s[j])||(s[j]>='0'&&s[j]<='9'));j++){
                tmp+=s[j];
            }
            res.push_back(tmp);
            i=j-1;//常量,宏,变量都可以按照这个方式处理
        }
        return res;
    }
    
    int main(){
    
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
    
        cin>>n;
        {
            string s,t;char c;
            getline(cin,s);
            for(int i=1;i<=n;i++){
                cin>>c>>s>>s;
                //特判#号和define分开的情况
                def[s]=i;
                getline(cin,t);
                expr[i]=mkexp(t);
            }
            getline(cin,t);
            expr[0]=mkexp(t);
        }
        memset(prio,-1,sizeof(prio));
        dfs(0);
        cout<<"OK"<<endl;//由于不合法会退出,这里可以直接输出合法
    
        return 0;
    }
    

    结尾

    祝你们一次AC!虽然人家是写挂好多次的说。。。再看,再看就诅咒你也写挂!哼~

  • 相关阅读:
    CentOS yum 源的配置与使用
    在css当中使用opacity
    CSS position属性absolute relative等五个值的解释
    uni APP 微信小程序获取授权的微信信息
    vue-admin-element 打包发布后IE报错的问题
    RMAN恢复数据文件
    怎么删除表空间对应的某一个数据文件
    Oracle存储过程、函数、包加密wrap
    Oracle加密解密
    Interval 用法总结
  • 原文地址:https://www.cnblogs.com/BlahDuckling747/p/12026484.html
Copyright © 2011-2022 走看看