【洛谷 P7073】 表达式【栈】

5 篇文章 0 订阅
3 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


解题思路

小知识:
在这里插入图片描述

后缀表达式求值,显然用栈。
建议使用手写栈,因为它很好写,常数还低 (至少CCF不会给你开O2)

这道题目最终让我们求的是某一个变量改变会不会对最终的值造成影响。

我们不妨设立 f f f数组,用 f i f_i fi表示第ii个数或运算的改变会直接影响到哪一个运算的结果。特别的,若 f i = 0 f_i=0 fi=0,则表示第ii个数或运算对其他结果都没有影响。

  • 当运算为KaTeX parse error: Expected 'EOF', got '&' at position 2: x&̲y时:
  1. x为0时,y无法造成任何影响;
  2. y为0时,x无法造成任何影响。
  • 当运算为 x ∣ y x|y xy时:
  1. x为1时,y无法造成任何影响;
  2. y为1时,x无法造成任何影响。
  • 当运算为 x ! y x!y x!y时:x一定会造成影响。

那么修改一个变量,只要从它往上走,看最终能不能影响最后一个运算的结果即可。


代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
struct c{
	int cnt,pl;
}lyx[1005000],k,z;//值(cnt)和位置(pl)
int j,y,n,m,ans,top,l,s[1005000],e[1005000],x[1005000],f[1005000],a[1005000];
/*
e表示每个运算:
若e[i]>0则e[i]就是题目中的 X [e[i]]
若e[i]=-1则表示&运算
若e[i]=-2则表示|运算
若e[i]=-3则表示!运算
l是e的长度
x[i]表示x[i]在e中的位置
f意义同上
*/
char ss[3030];
int main(){
	while(1)
	{
		cin>>ss;
		if(ss[0]>='0'&&ss[0]<='9')break;
		l++;
		if(ss[0]=='x')
		{
			sscanf(ss+1,"%d",&e[l]);
			x[e[l]]=l;
		}
		if(ss[0]=='!')e[l]=-1;
		if(ss[0]=='&')e[l]=-2;
		if(ss[0]=='|')e[l]=-3;
	}
	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)
		{
			lyx[++top].cnt=a[e[i]];
			lyx[top].pl=i;
		}
		if(e[i]==-1)
		{
			k=lyx[top];
			lyx[top].cnt=!k.cnt;
			lyx[top].pl=i;
			f[k.pl]=i;	
		}
		if(e[i]==-2)
		{
			k=lyx[top];
			top--;
			z=lyx[top];
			lyx[top].pl=i;
			lyx[top].cnt=k.cnt&z.cnt;
			if(k.cnt==1) f[z.pl]=i;
			if(z.cnt==1) f[k.pl]=i;
		}
		if(e[i]==-3)
		{
			k=lyx[top];
			top--;
			z=lyx[top];
			lyx[top].pl=i;
			lyx[top].cnt=k.cnt|z.cnt;
			if(k.cnt==0) f[z.pl]=i;
			if(z.cnt==0) f[k.pl]=i;
		}
	}
	ans=lyx[top].cnt;
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&y);
		for(j=x[y];f[j];j=f[j]); //一路找到它最终会改变哪个值
		if(j==l) //最后一个运算是l,那么当它会改变l时将原答案取反
			printf("%d\n",!ans);
		else printf("%d\n",ans);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值