Codeforces Beta Round #7 E Defining Macros

一道关于表达式的题目。。。

思路参考了xhr大大的题解,在此贴上:

算法讨论
我们考虑一个宏是否是“安全”的,经过观察和一些实验,可以发现,只有以下4种状态:
•状态1(s1):这个宏完全安全,以任何方式使用该宏都没问题。
•状态2(s2):这个宏不安全,只要表达式中出现该宏,都会导致表达式不安全。
•状态3(s3):这个宏部分安全,仅当这个宏与’*’,’/’连接时,或出现在’-’后面时,才会使表达式不安全。
•状态4(s4):这个宏部分安全,仅当这个宏出现在’/’后面时,才会使表达式不安全。有了这4个状态,我们只需推出状态之间的转移即可。
•如果表达式没有使用任何运算符或括号或宏(也就是s仅仅是个单独的变量),那么安全级别显然是s1
•如果表达式s是(t)的形式(被一对括号括起来的表达式t),那么如果t的状态不是s2,则s的状态是s1,否则s的状态是s2
•我们找到表达式s中,最后一次运算的符号,设其为op,设其两侧表达式分别为t1和t2。我们进行以下分类讨论:
–显然,如果t1或t2的安全状态是s2,则s的状态也是s2;–如果op是’+’,那么s的状态是s3;
–如果op是’-’,那么,如t2状态是s3,则s状态是s2,否则s状态是s3
–如果op是’*’,那么,如t1或t2状态是s3,则s状态是s2,否则s状态是s4
–如果op是’/’,那么,如t1或t2状态是s3,或t2状态是s4,则s状态是s2,否则s状态是s4于是,此题得到了解决。时间复杂度O(n∗len2),如果愿意追求更好的复杂度,可以建出表达式树,从而做到O(N∗len)

 

实现时主要的点是先将表达式化作一个类似token流的东西,然后在其中找出最后一次运算(不是最后一个)的符号,根据两边的表达式类型递归求出整个表达式的类型

token流中1,2,3,4 表示 宏的四个状态;5,6,7,8表示+-*/

贴上代码:

#include <cstring>
#include <iostream>
#include <map>
#include <algorithm>
#include <stack>
#include <string>
#include <set>
#include <cmath>
#include <queue>
#include <cstdio>
#include <sstream>
#include <vector>
using namespace std;
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define repm(i, j, k) for(int i = j; i >= k; i--)
#define mem(a) memset(a, 0, sizeof(a))
#define mp make_pair
typedef long long ll;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
char w[200];
string l;
map<string, int> all;
int msusp[200];
int as[110][110];


int ans(int l, int r, vector<int> vec) {
    if(l == r) return as[l][l] = vec[l];
    if(as[l][r] != 0x7f7f7f7f) return as[l][r];
    else {
        int id = l + 1;
        for(int i = l + 1; i < r; i += 2) {
            if(!(vec[id] <= 6 && vec[i] >= 7))
            id = i;
        }
        if(ans(l, id - 1, vec) == 2 || ans(id + 1, r, vec) == 2) return as[l][r] = 2;
        if(vec[id] == 5) return as[l][r] = 3;
        if(vec[id] == 6) {
            if(ans(id + 1, r, vec) == 3) return as[l][r] = 2;
            return as[l][r] = 3;
        } 
        else if(vec[id] == 7) {
            if(ans(l, id - 1, vec) == 3 || ans(id + 1, r, vec) == 3) return as[l][r] = 2;
            return as[l][r] = 4;
        }
        else if(vec[id] == 8) {
            if(ans(l, id - 1, vec) == 3 || ans(id + 1, r, vec) == 3 || ans(id + 1, r, vec) == 4) return as[l][r] = 2;
            return as[l][r] = 4;
        }
    }
}
int calc(int a, int b) {
    vector<int> vec;
    vec.clear();
    int last = -1, susp = 0, d = 0;
    string cur = "";
    rep(j, a, b) {
        if(j < b && (l[j] >= 'a' && l[j] <= 'z' || l[j] >= 'A' && l[j] <= 'Z' || l[j] >= '0' && l[j] <= '9'))
        cur += l[j];
        else {
            if(cur != "") {
                if(d == 0) {
                    int t = -1, csusp = 1;
                    if(all.find(cur) != all.end()) {
                        t = all[cur];
                        csusp = msusp[t];
                    }
                    vec.push_back(csusp);
                }
                cur = "";
            }
        }
        if(j == b) break;
        if(l[j] == '(') {
            if(d == 0) last = j + 1;
            d++;
        }
        if(l[j] == ')') {
            d--;
            if(d == 0) {
                int csusp = calc(last, j);
                if(csusp != 2)
                csusp = 1;
                vec.push_back(csusp);
            }
        }
        if(d == 0 && l[j] == '+') vec.push_back(5);
        if(d == 0 && l[j] == '-') vec.push_back(6);
        if(d == 0 && l[j] == '*') vec.push_back(7);
        if(d == 0 && l[j] == '/') vec.push_back(8);
    }
    memset(as,0x7f,sizeof(as));
    return ans(0, vec.size() - 1, vec);
}
int n;
int main()
{
    scanf("%d\n",&n);
    rep(i, 0, n) {
        string s, ss;
            gets (w);
        istringstream in(w);
        if(i < n) {
            in >> s;
            if (s.size () == 1) in >> s;
            in >> s;
        }
        l = "";
        while(in >> ss) l += ss;
        msusp[i] = calc(0, l.size());
        if(i < n)
        all[s] = i;
    }
    if(msusp[n] != 2) cout << "OK" << endl;
    else cout << "Suspicious" << endl;
}

 

转载于:https://www.cnblogs.com/OZTOET/p/5192797.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值