首页 > 其他分享 >表达式的值【题解】

表达式的值【题解】

时间:2023-01-12 16:23:17浏览次数:40  
标签:le int 题解 样例 MAXN 表达式 dp

[NOIP2011 普及组] 表达式的值

题目描述

对于1 位二进制变量定义两种运算:

运算的优先级是:

  1. 先计算括号内的,再计算括号外的。

  2. “× ”运算优先于“⊕”运算,即计算表达式时,先计算× 运算,再计算⊕运算。例如:计算表达式A⊕B × C时,先计算 B × C,其结果再与 A 做⊕运算。

现给定一个未完成的表达式,例如_+(_*_),请你在横线处填入数字$0 $或者\(1\) ,请问有多少种填法可以使得表达式的值为$0 $。

输入格式

共 2 行。

第1 行为一个整数 \(L\),表示给定的表达式中除去横线外的运算符和括号的个数。

第2 行为一个字符串包含 \(L\) 个字符,其中只包含’(’、’)’、’+’、’*’这\(4\) 种字符,其中’(’、’)’是左右括号,’+’、’*’分别表示前面定义的运算符“⊕”和“×”。这行字符按顺序给出了给定表达式中除去变量外的运算符和括号。

输出格式

共1 行。包含一个整数,即所有的方案数。注意:这个数可能会很大,请输出方案数对$10007 $取模后的结果。

样例 #1

样例输入 #1

4
+(*)

样例输出 #1

3

提示

【输入输出样例说明】

给定的表达式包括横线字符之后为:_+(_*_)

在横线位置填入(0 、0 、0) 、(0 、1 、0) 、(0 、0 、1) 时,表达式的值均为0 ,所以共有3种填法。

【数据范围】

对于 \(20\%\) 的数据有 \(0 \le L \le 10\)。

对于 \(50\%\) 的数据有 \(0 \le L \le 1,000\)。

对于 \(70\%\) 的数据有 \(0 \le L \le 10,000\) 。

对于 \(100\%\)的数据有 \(0 \le L \le 100,000\)。

对于\(50\%\) 的数据输入表达式中不含括号。

浅浅分析一波

首先一看数据范围\(0 \le L \le 100000\),回溯的梦想破灭了fuck !

怎么做?

  • 首先,他给的是一个不完整的序列,第一个思路就是把他补齐,例如样例

  • \(+(*)=?+(?*?)\)

  • 然后?

  • 如果我们要算,那么首先就是确定运算优先级,怎么确定?

  • 当然是转成后缀表达式,例如样例

  • \(?+(?*?)=??*?+\)

  • 然后?

  • 由于他问的是方案数,还要\(mod\)一个数,很容易想到动态规划

  • 想状态?

  • 很容易想到对于一个操作符,他的方案数由前两个状态得来

  • 什么意思?

  • 例如样例\(??*?+\),看到第一个乘号,他的方案数就是前两个\(?\)得来的(问号为1)

  • 于是,就变成了\(??+\),第一个\(?\)是\(??*\)变成的

  • 于是,加法就由前两个\(?\)得来的,于是可得下面代码

#include<bits/stdc++.h>

using namespace std;
const int MAXN=1e5+7,mod=1e4+7;
int f[MAXN][2],n,m,len;
char s[MAXN],ss[MAXN];
//f[i][0]为这个位置为0的方案书
//f[i][1]为这个位置为1的方案
//第一步,确定运算顺序
//第二步,dp
//if(s[i-1]=='+') dp[i][0]=dp[i-1][0]
//dp[i][1]=dp[i-1][0]+dp[i-1][1]*2
//if(s[i-1]=='*') dp[i][0]=dp[i-1][0]*2+dp[i-1][1]
//dp[i][1]=dp[i-1][1]
void get_str(int l,int r){
	for(int i=l;i<=r;i++) if(ss[i]=='*') s[++len]=ss[i],ss[i]=' ';
	for(int i=l;i<=r;i++) if(ss[i]=='+') s[++len]=ss[i],ss[i]=' ';
}
void init(){
	stack<int> t;
	ss[0]='(',ss[m+1]=')';
	for(int i=0;i<=m+1;i++){
		if(ss[i]==')'){
			get_str(t.top()+1,i-1);
			t.pop();
		}
		else if(ss[i]=='(') t.push(i);
	}
}
int main(){
	scanf("%d%s",&n,ss+1);
	m=strlen(ss+1);
	init();
	f[1][1]=1,f[1][0]=1;
	for(int i=2;i<=len+1;i++) {
		if(s[i-1]=='*') f[i][0]=(f[i-1][0]*2+f[i-1][1])%mod,f[i][1]=f[i-1][1]%mod;
		if(s[i-1]=='+') f[i][0]=f[i-1][0]%mod,f[i][1]=(f[i-1][0]+f[i-1][1]*2)%mod;
	}
	cout<<f[len+1][0];
	return 0;
}
  • \(20\)分,为什么?

  • 我们来看一个样例\((+)*(+)\),后缀表达式为\(??+??+*\)

  • 我们来看最后一个乘号,根据是上面代码,\(*\)由\(?,+\)转移过来,真的是这样吗?

  • 很容易想到,肯定不是这样的,就说明这个\(dp\)有问题

  • 咋办?

  • 很容易想到用一个,把求出的状态推进去,于是就有了满分代码

\(Code\)


#include<bits/stdc++.h>

using namespace std;
struct node{int l,y;};
const int MAXN=1e6+7,mod=1e4+7;
char a[MAXN],S[MAXN],s[MAXN];
int n,m,len;
stack<node> ans;
void print(){
	for(int i=1;i<=len;i++) cout<<s[i];
	cout<<endl;
}
int get_y(char s){
	if(s=='(') return 0;
	if(s=='+') return 1;
	if(s=='*') return 2;
}
void change(){
	stack<char> t;
	for(int i=1;i<=m;i++){
		if(S[i]=='_'){
			s[++len]=S[i];
		}else if(t.empty()){
			t.push(S[i]);
		}else if(S[i]=='('){
			t.push(S[i]);
		}else if(S[i]==')'){
			while(!t.empty()&&t.top()!='(') s[++len]=t.top(),t.pop();
			t.pop();
		}else if(get_y(t.top())>=get_y(S[i])){
			while(!t.empty()&&get_y(t.top())>=get_y(S[i])){s[++len]=t.top();t.pop();}
			t.push(S[i]);
		}else{
			t.push(S[i]);
		}
	} 
	while(!t.empty())s[++len]=t.top(),t.pop();
}
int main(){
	scanf("%d%s",&n,a+1);
	n=strlen(a+1);
	for(int i=1;i<=n;i++){
		if(a[i-1]==')') S[++m]=a[i]; 
		else if(a[i]!='('&&a[i]!=')')S[++m]='_',S[++m]=a[i];
		else if(a[i]=='(') S[++m]=a[i];
		else S[++m]='_',S[++m]=a[i];
	}
	if(a[n]!=')') S[++m]='_';
	change();
//	print();
	for(int i=1;i<=len;i++){
		if(s[i]=='_'){
			ans.push(node{1,1});
		}else{
			node qian=ans.top();ans.pop();
			node hou=ans.top();ans.pop();
			int ysum=0,lsum=0;
			if(s[i]=='+'){
				ysum=(qian.l*hou.y%mod+qian.y*hou.l%mod+qian.y*hou.y%mod)%mod;
				lsum=(qian.l*hou.l)%mod;
			}else{
				lsum=(qian.l*hou.y%mod+qian.y*hou.l%mod+qian.l*hou.l%mod)%mod;
				ysum=(qian.y*hou.y)%mod;
			}
			ans.push(node{lsum,ysum});
		}
	}
	cout<<ans.top().l;
	return 0;
}
/*
0
(+)*(+)
——+——+*
*/

标签:le,int,题解,样例,MAXN,表达式,dp
From: https://www.cnblogs.com/Phrvth/p/17046991.html

相关文章

  • [NOIP2017 普及组]跳房子 【题解】
    题目背景NOIP2017普及组T4题目描述跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。跳房子的游戏规则如下:在地面上确定一个起点,然后在起点......
  • 洛谷 P8077 [WC2022] 序列变换 题解
    题目链接。WC2023之前补一下WC2022的题,参考了官方题解。首先,把括号序列转化为二叉树,\(\texttt{(A)B}\)转为一个点的左子树是\(A\),右子树是\(B\)。相当于括号序列先......
  • 1.8模拟赛题解
    T1考虑每次反弹后,球的运动轨迹都会偏移\(2\beta\),总偏移量即为\(2k\beta\),而最后需要回到原点,因此\(360|2k\beta\),简单求\(\gcd\)即可。T2设\(ans_k\)表示出现过......
  • 1.11模拟赛题解
    T1对于方阵\(A\),考虑其反方阵\(A'\)。容易发现\(A\)与\(A'\)的权值和相同,而其中必有一个与\(B\)的差不超过\(\lfloor\frac{nm}{2}\rfloor\),因此判断一下哪个满足......
  • 1.9模拟赛题解
    T1从左到右扫描,首先如果\(a_i<b_i\)那么一定无解,否则不断在其右边找最近的\(j\)使得\(a_j\in[b_i,a_i]\),把\(a_i\)和\(a_j\)交换。感性理解这是对的。T2先证操......
  • 1.12模拟赛题解
    T1容易知道答案为原图的最大子二分图大小。枚举每个点在二分图的左边还是右边,计算出答案。时间复杂度\(O(2^n\timesm)\)。T2考虑递推构造方案。假设现在已经有了一组......
  • POI Excel格式报表生成 同步下载问题解决
    前言解决POI导出功能,过时方法和新增样式放在最下面或者参考下文POI样式调节0.maven(新版本)<poi.version>4.1.2</poi.version> <dependency> <groupId>org.ap......
  • P6751 [IOI2019]视觉程序 题解--zhengjun
    提供一种简介易懂的做法。首先曼哈顿距离的绝对值比较难处理,所以可以转成切比雪夫距离。具体地说,就是\((x,y)\)变成\((x+y,x-y)\)(接下来所述的坐标都是变换后的)。这......
  • 常用正则表达式
    一、js正则表达式 1、密码强度,至少包含大小写字母、特殊字符、数字三种及以上,长度8~20位varreg=/(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\W_!@#$%^&*`~()-+=]+$)(?![......
  • YACS 2022年12月月赛 乙组 T1 拼接单词 题解
    一道结论题,代码相当的短。我们先来考虑会拼出重复的情况:那必定是第一个字符串里有一个$a$(其他的也行),第二个也有一个$a$。那么我们就可以选择拿第一个字符串$a$前面的......