洛谷 CF7E Defining Macros 题解

题意翻译

题目给了一系列C + +的宏定义,问你一个表达式是否是“安全"的。安全的定义是,展开后的表达式中,所有的宏在计算过程中都被作为一个整体运算。

如#define sumx十y后,2 sum就会被替换乘2x+y 此时此时因为乘号优先级比加号高,导致宏在实际计算中被拆开了,可能产生错误。

宏的个数<=10,每个表达式长度<=10.只有四则运算和括号。

Translated by liyifeng

题目描述

Most C/C++ programmers know about excellent opportunities that preprocessor #define directives give; but many know as well about the problems that can arise because of their careless use.

In this problem we consider the following model of #define constructions (also called macros). Each macro has its name and value. The generic syntax for declaring a macro is the following:

#define macro_name macro_value

After the macro has been declared, "macro_name" is replaced with "macro_value" each time it is met in the program (only the whole tokens can be replaced; i.e. "macro_name" is replaced only when it is surrounded by spaces or other non-alphabetic symbol). A "macro_value" within our model can only be an arithmetic expression consisting of variables, four arithmetic operations, brackets, and also the names of previously declared macros (in this case replacement is performed sequentially). The process of replacing macros with their values is called substitution.

One of the main problems arising while using macros — the situation when as a result of substitution we get an arithmetic expression with the changed order of calculation because of different priorities of the operations.

Let's consider the following example. Say, we declared such a #define construction:

#define sum x + y

and further in the program the expression "2 * sum" is calculated. After macro substitution is performed we get "2 * x + y", instead of intuitively expected "2 * (x + y)".

Let's call the situation "suspicious", if after the macro substitution the order of calculation changes, falling outside the bounds of some macro. Thus, your task is to find out by the given set of #define definitions and the given expression if this expression is suspicious or not.

Let's speak more formally. We should perform an ordinary macros substitution in the given expression. Moreover, we should perform a "safe" macros substitution in the expression, putting in brackets each macro value; after this, guided by arithmetic rules of brackets expansion, we can omit some of the brackets. If there exist a way to get an expression, absolutely coinciding with the expression that is the result of an ordinary substitution (character-by-character, but ignoring spaces), then this expression and the macros system are called correct, otherwise — suspicious.

Note that we consider the "/" operation as the usual mathematical division, not the integer division like in C/C++. That's why, for example, in the expression "a*(b/c)" we can omit brackets to get the expression "a*b/c".

输入输出格式

输入格式:

 

The first line contains the only number nn ( 0<=n<=1000<=n<=100 ) — the amount of #define constructions in the given program.

Then there follow nn lines, each of them contains just one #define construction. Each construction has the following syntax:

#define name expression

where

  • name — the macro name,
  • expression — the expression with which the given macro will be replaced. An expression is a non-empty string, containing digits,names of variables, names of previously declared macros, round brackets and operational signs +-*/. It is guaranteed that the expression (before and after macros substitution) is a correct arithmetic expression, having no unary operations. The expression contains only non-negative integers, not exceeding 10^{9}109 .

All the names (#define constructions' names and names of their arguments) are strings of case-sensitive Latin characters. It is guaranteed that the name of any variable is different from any #define construction.

Then, the last line contains an expression that you are to check. This expression is non-empty and satisfies the same limitations as the expressions in #define constructions.

The input lines may contain any number of spaces anywhere, providing these spaces do not break the word "define" or the names of constructions and variables. In particular, there can be any number of spaces before and after the "#" symbol.

The length of any line from the input file does not exceed 100 characters.

 

输出格式:

 

Output "OK", if the expression is correct according to the above given criterion, otherwise output "Suspicious".

输入输出样例

输入样例#1: 复制

1
#define sum x + y
1 * sum

输出样例#1: 复制

Suspicious

输入样例#2: 复制

1
#define sum  (x + y)
sum - sum

输出样例#2: 复制

OK

输入样例#3: 复制

4
#define sum  x + y
#define mul  a * b
#define div  a / b
#define expr sum + mul * div * mul
expr

输出样例#3: 复制

OK

输入样例#4: 复制

3
#define SumSafe   (a+b)
#define DivUnsafe  a/b
#define DenominatorUnsafe  a*b
((SumSafe) + DivUnsafe/DivUnsafe + x/DenominatorUnsafe)

输出样例#4: 复制

Suspicious

题解思维

考虑什么时候会Suspicious
如果是l/r, 当ll有+or-或r有+or-or*or/就会出错。
(有指的是最外一层)
其他同理。
所以只要dp,记录最外一层是否存在+or-,*or/即可。
预处理每个左括号对应的右括号。
复杂度线性。
读入有点麻烦。

将这个程序翻译过来,就是 (((a+b))+a/b/a/b+x/a*b)

在这个程序中,a/b/a/b和x/a*b可能会出现错误,这是由运算符之间的关系造成的。

我们可以观察一下四种运算,可以发现情况可以分为四种。

  1. 完全正确

  2. 完全不正确

  3. 在减号后或与乘除相连时出错

  4. 在除号后出错

我们找到一个宏定义表达式的优先级最后运算符,把式子分为两部分,如果两部分都是第2种情况,那整个式子也是第2种。

如果运算符为加,整个式子会是第3种情况。

如果运算符为减,则仅当右部是第3种情况时,整体为第2种情况,否则整体为第3种情况。

如果运算符为乘,则在两部分至少有一个为第3种情况时,整体为第2种情况,否则整体为第3种情况。

如果运算符为除,则在两部分至少有一个为第3种情况或右部为第4种情况时,整体为第2种情况,否则整体为第3种情况。

如果两端有括号,先去括号,判断括号中的表达式的种类,没有的话就是第一种情况。

最后对最后那个程序进行判断,如果是第2种情况,就是不正确,否则就是正确。

Accept Code:

#include<bits/stdc++.h>
using namespace std;
map<string,int> mapp;
int n,m;
string s,s1,s2,ss,s3;
int judge(int l,int r)
{
    int flag=0,pos=0;
    for (int i=r;i>=l;i--)
    {
        if (s[i]=='(') flag++;
        if (s[i]==')') flag--;
        if (pos==0&&flag==0&&(s[i]=='*'||s[i]=='/')) pos=i;
        if (flag==0&&(s[i]=='+'||s[i]=='-'))
        {
            int t1=judge(l,i-1),t2=judge(i+1,r);
            if (t1==2||t2==2) return 2;
            if (s[i]=='+') return 3;
            if (s[i]=='-'&&t2==3) return 2;
            if (s[i]=='-') return 3;
        }
    }
    if (pos!=0)
    {
        int t1=judge(l,pos-1),t2=judge(pos+1,r);
        if (t1==2||t2==2) return 2;
        if (s[pos]=='*'&&(t1==3||t2==3)) return 2;
        if (s[pos]=='*') return 4;
        if (s[pos]=='/'&&(t1==3||t2==3||t2==4)) return 2;
        if (s[pos]=='/') return 4;
    }
    else if (s[l]=='('&&s[r]==')')
    {
        if (judge(l+1,r-1)==2) return 2;
        else return 1;
    }
    else
    {
      ss="";
      for (int i=l;i<=r;i++)
      ss+=s[i];
      if (mapp[ss]!=0) return mapp[ss];
      else return 1;
    }
}
int main()
{
    cin>>n;
    for (int i=1;i<=n;i++)
    {
        int tot=0;
        int t1=0,t2=0;
        int j=1;
        cin>>s1;
        if (s1[s1.length()-1]=='#') cin>>s1;
        cin>>s1;
        getline(cin,s2);
        s="";
        for (int j=0;j<=s2.length()-1;j++)
        if (s2[j]!=' ') s+=s2[j];
        int ans=judge(0,s.length()-1);
        mapp[s1]=ans;
    }
    int tot=0;
    s3="";
    s="";
    getline(cin,s3);
    for (int i=0;i<s3.length();i++)
    if (s3[i]!=' ') s+=s3[i];
    int ans=judge(0,s.length()-1);
    if (ans!=2) printf("OK\n");
    else printf("Suspicious\n");
    return 0;
} 

 

上一篇:C/C++ 中的宏/Macro


下一篇:BLheli-F330电调相关实验方案