7073 表达式

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值