ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

nflsoj 20034 #12423. 「NOIP2021模拟赛0913华二」二进制式

2021-09-21 15:02:11  阅读:224  来源: 互联网

标签:cnt 华二 nflsoj int 0913 xor 500010 取值 表达式


小W 写了一个二进制式,其中包含个 \(n\) 变量和 \(n-1\) 个符号,每个变量的值只能取 \(0\) 或 \(1\) ,每个符号已经确定,是 and,or,xor 中的一个,但是变量的取值却是没有被固定的。

对于一个变量 $l \(,\)f(l)$ 定义表示:当除 \(l\) 外其他变量的取值固定时,\(l\) 取 \(0\) 和取 \(1\) 两种状态下,表达式的值不相等的概率。

例如对于式子 \(x\ or\ y\),有 \(f(x)=\frac{1}{2}\),因为当 \(y=0\) 时,\(x\) 的两种取值会导致表达式的值不相等;但 \(y=1\) 当时,\(x\) 的两种取值无法影响到整个表达式的值(表达式的值始终为 \(1\) ),所以 \(x\) 取 \(0\) 和取 \(1\) 两种状态导致表达式的值不相等的概率为 \(\frac{1}{2}\) 。

再例如对于式子\(x\ xor\ y\),有 \(f(x)=1\) ,因为无论 \(x\) 的取值如何,\(x\) 的取值不同时,\(x\ xor\ y\) 的值总是不同的。

小 W 想要你求出给定的二进制式中所有 \(f(l)\) 的值,结果对 \(998244353\) 取模 .

在本题中,一个表达式 \(Expr\) 的定义是:

  1. \(Expr\) 可以是一个单独的变量;
  2. 否则,\(Expr\) 将表示成 \((Expr1\ op\ Expr2)\) ,其中 \(Expr1\) 和 \(Expr2\) 分别是表达式,\(op\) 是一种运算符,输入保证不会省略任何括号(包括整个表达式外的括号)。

link: 题目描述

首先,根据正则表达式,可以建出一棵二叉树,

用 \(f(x,0/1)\) 表示子树 \(x\) 的值为 \(0/1\) 的方案数 . 这个是可以 \(O(n)\) 求得的 .

接着,考虑 \(g(x)\) 表示子树 \(x\) 内的数可 \(0\) 可 \(1\) 时子树外有多少种方案使得答案可 \(0\) 可 \(1\) .

设 \(x\) 的左儿子为 \(a\) ,右儿子为 \(b\) ,转移方程为 :

如果操作为 \(and\) ,

\(g(a)=\sum g(x)dp(b,i)\),\(i\) 满足 \(i\&1\not=i\&0\).

如果操作为 \(or\) ,

\(g(a)=\sum g(x)dp(b,i)\) ,\(i\) 满足 \(i|1\not=i|1\) .

如果操作为 \(xor\),

\(g(a)=\sum g(x)dp(b,i)\), \(i\) 满足 \(i\ xor\ 1\not=i\ xor\ 0\) .

对 \(b\) 同理 .

那么,对于每个叶子节点的 \(g(x)\) 就是当 \(x\) 取 \(0\) 和 \(x\) 取 \(1\) 时不相同的方案数 .

如果想要改成概率,再乘上 \(2^{n-1}\) 的逆元就可以了 .

时间复杂度 : \(O(n)\)

空间复杂度 : \(O(n)\)

code

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int n;
string s;
stack<int>st;
int cnt=0;
char c[500010];
bool leaf[500010];
int L[500010],R[500010]; // À¨ºÅ 
int son[500010][2]; 
int num[500010],id[500010];
int build(int l,int r){
	if(R[l]==r)return build(l+1,r-1);
	if(l==r){
		leaf[cnt]=true;
		id[cnt]=num[l];
		return cnt++;
	}
	if(r-l+1==3){
		int a=build(l,l),b=build(r,r);
		son[cnt][0]=a;son[cnt][1]=b;
		c[cnt]=s[l+1];
		return cnt++;
	}
	int pos=-1;
	for(int i=l;i<=r;i++){
		if(s[i]=='('){
			pos=i;
			break;
		}
	}
	if(pos==l){
		int a=build(pos+1,R[pos]-1),b=build(R[pos]+2,r);
		son[cnt][0]=a;son[cnt][1]=b;
		c[cnt]=s[R[pos]+1];
		return cnt++;
	}
	if(R[pos]==r){
		int a=build(l,pos-2),b=build(pos+1,R[pos]-1);
		son[cnt][0]=a;son[cnt][1]=b;
		c[cnt]=s[pos-1];
		return cnt++;
	}
}
inline void upd(int &x,int y){x=(x+y)%mod;}
int dp[500010][2];
void dfs(int x){
	if(leaf[x]){
		dp[x][0]=dp[x][1]=1;
		return;
	}
	int a=son[x][0],b=son[x][1];
	dfs(a);
	dfs(b);
	for(int i=0;i<2;i++)for(int j=0;j<2;j++){
		if(c[x]=='|')upd(dp[x][i|j],1ll*dp[a][i]*dp[b][j]%mod);
		if(c[x]=='&')upd(dp[x][i&j],1ll*dp[a][i]*dp[b][j]%mod);
		if(c[x]=='^')upd(dp[x][i^j],1ll*dp[a][i]*dp[b][j]%mod);
	}
}
int ans[500010];
int f[500010];
void dfs2(int x){
	if(leaf[x]){
		ans[id[x]]=f[x];
		return;
	}
	int a=son[x][0],b=son[x][1];
	for(int i=0;i<2;i++){
		if(c[x]=='|'){
			if((i|0)!=(i|1)){
				upd(f[a],1ll*f[x]*dp[b][i]%mod);
				upd(f[b],1ll*f[x]*dp[a][i]%mod);
			}
		}
		if(c[x]=='&'){
			if((i&0)!=(i&1)){
				upd(f[a],1ll*f[x]*dp[b][i]%mod);
				upd(f[b],1ll*f[x]*dp[a][i]%mod);
			}
		}
		if(c[x]=='^'){
			if((i^0)!=(i^1)){
				upd(f[a],1ll*f[x]*dp[b][i]%mod);
				upd(f[b],1ll*f[x]*dp[a][i]%mod);
			}
		}
	}
	dfs2(a);
	dfs2(b);
}
inline int ksm(int x,int k){
	if(k==0)return 1;
	int res=ksm(x,k/2);
	res=1ll*res*res%mod;
	if(k&1)res=1ll*res*x%mod;
	return res;
} 
int main(){
	freopen("binary.in","r",stdin);
	freopen("binary.out","w",stdout);
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n>>s;
	if(n==1){
		cout<<"1\n";
		return 0;
	}
	for(int i=0;i<(int)s.size();i++)if(s[i]=='x')num[i]=cnt++;
	cnt=0;
	memset(L,-1,sizeof(L));
	memset(R,-1,sizeof(R));
	for(int i=0;i<(int)s.size();i++){	
		if(s[i]=='(')st.push(i);
		else if(s[i]==')'){
			R[st.top()]=i;
			L[i]=st.top();
			st.pop();
		}
	}
	memset(son,-1,sizeof(son));
	int r=build(0,(int)s.size()-1);
	dfs(r);
	f[r]=1;
	dfs2(r);
	int tot=ksm(2,n-1);
	for(int i=0;i<n;i++){
		int res=1ll*ans[i]*ksm(tot,mod-2)%mod;
		cout<<res<<"\n";
	}
	return 0;
}
/*inline? ll or int? size? min max?*/
/*
4
((x^x)|(x&x))
*/
/*
2
(x|x)
*/
/*
2
(x^x)
*/

标签:cnt,华二,nflsoj,int,0913,xor,500010,取值,表达式
来源: https://www.cnblogs.com/suadwm/p/15316618.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有