7073 表达式
其实这个题我不怎么理解,就是感觉很牛,很蓝,但是还很不会
先来理解一下题意:
给定一个逻辑表达式,是一个以后缀表达式的形式,然后给定几个操作,再取反这个操作的值,求表达式的值
然后这道题肯定是用栈来求,而且是手写的栈,虽然难操作,但是时间快
我们要求的是?某一个变量的改变会不会对最终的值造成影响
首先我们先设立一个f数组,用fi表示第i个数或运算的改变会直接影响到哪一个运算的结果
那么怎么求fi?
首先得分情况考虑
一个是and 一个or 一个nor
也就是&|!这三个表达式
然后呢就分了三种情况
如果是x&y那么不会影响,如果是x|y也不会影响,那么是!x绝对会影响
其实就没什么了,感觉这个题有点像动态规划了
#include<bits/stdc++.h>
using namespace std;
struct st //v表示值,id表示位置
{
st() {}
st(int id, int v) : id(id), v(v) {}
int id, v;
} tx, ty, s[1000001];//s是栈
char ss[1111]; //读入的字符串
int n, q;
int res, x, y;
int a[1000001], e[2000001], l = 0;
int xe[1000001], f[2000001], stop = 0;//stop栈顶元素
/*
e表示每个运算:
若e[i]>0则e[i]就是题目中的x[e[i]]
l是e的长度
xe[i]表示x[i]在e中的位置
f意义同上
*/
inline void push(st x)
{
s[++stop] = x;
}
inline void pop()
{
stop--;
}
inline st top() //三个操作都是手写的
{
return s[stop];
}
int main()
{
while ( 1 )
{
scanf("%s", ss);
if ( ss[0] >= '0' && ss[0] <= '9' ) break;//数字就退出,因为是后缀形式
l++;//计算符号的长度
if ( ss[0] == 'x' )//如果是未知数
{
sscanf(ss + 1, "%d", e + l);//sscanf直接赋值
xe[e[l]] = l;//存储xi的位置
}
if ( ss[0] == '&' ) e[l] = -1;
if ( ss[0] == '|' ) e[l] = -2;
if ( ss[0] == '!' ) e[l] = -3;//存储三个符号,为e数组
}
sscanf(ss, "%d", &n);
for ( int i = 1 ; i <= n ; i++ ) scanf("%d", a + i);//输入变量
for ( int i = 1 ; i <= l ; i++ )//求出f
{
if ( e[i] > 0 ) push(st(i, a[e[i]]));//题目中的操作指数
if ( e[i] == -3 )//!
{
tx = top();//取出栈顶
pop();
push(st(i, !tx.v));//会影响值,于是直接取反
f[tx.id] = i;
}
if ( e[i] == -2 )//|
{
tx = top();
pop();
ty = top();//保存最近的
pop();
push(st(i, tx.v || ty.v));//不会影响
if ( !ty.v ) f[tx.id] = i;
if ( !tx.v ) f[ty.id] = i;
}
if ( e[i] == -1 ) //&
{
tx = top();
pop();
ty = top();
pop();
push(st(i, tx.v && ty.v));
if ( ty.v ) f[tx.id] = i;
if ( tx.v ) f[ty.id] = i;
}
}
res = top().v;//最终的答案
scanf("%d", &q);//输入询问
for ( int i = 1 ; i <= q ; i++ )
{
scanf("%d", &x);//输出未知数
for ( y = xe[x] ; f[y] ; y = f[y] );//一路找,看看哪一个会更新自己
//显然最后一个运算是l,那么当它会改变l时将原答案取反
printf("%d\n", y == l ? !res : res);//找答案
}
return 0;
}