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

小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)
*/
上一篇:nflsoj 20034 #12433. 「NOIP2021模拟赛0916南外」排列


下一篇:SOFAStack Meetup#5 上海站 容器沙箱专场