ZROI – 19普及组 – Day2 – T4 – 与非门树
题意
给定一棵 nnn 个节点的有根树,每个点有点权。对于所有叶子节点,点权为 000 或 111。非叶子节点分为两类,对于第一类,点权为其所有儿子节点的点权与非和;对于第二类,点权恒为 hi∈[0,1]h_i\in[0, 1]hi∈[0,1],题目给定 hih_ihi.
现在给叶子节点赋值。
存在 AAA 种不同的赋值方法使得:若将所有第二类点变为第一类点,根节点的点权不变,一共存在 BBB 种不同的赋值方法。
求 ABmod998244353\frac{A}{B}\bmod 998244353BAmod998244353.
解法
上面的部分只用于理解题意,与Solution部分基本无关。
考虑树形DP.
定义 cnt[x]\operatorname{cnt}[x]cnt[x] 表示与 xxx 直接相连的叶子节点个数。
定义 xxx 的理论值为:如果所有的与非门都能正常工作,xxx 的点权。
定义 xxx 的实际值为:在实际情况下, xxx 的点权。
设置状态 DPx,0/1,0/1\operatorname{DP}_{x,0/1,0/1}DPx,0/1,0/1 表示 xxx 的点权,理论值为 0/10/10/1,实际值为 0/10/10/1 时的赋值方法种类数量。
Part\rm{Part}Part 1\rm{1}1
如果 xxx 不是一个坏了的与非门,那么考虑此时四种状态如何从 xxx 的儿子转移上来。
DPx,0,0\operatorname{DP}_{x, 0, 0}DPx,0,0 的转移
对于 DPx,0,0\operatorname{DP}_{x, 0, 0}DPx,0,0,理论值和实际值都为 000,所以对于所有 xxx 的儿子,理论值和实际值必须都为 111,即:
DPx,0,0=∏i是x的儿子DPi,1,1\operatorname{DP}_{x, 0, 0} = \prod_{\text{i是x的儿子}}\operatorname{DP}_{i, 1, 1} DPx,0,0=i是x的儿子∏DPi,1,1
DPx,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1 的转移
对于 DPx,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1,理论值为 000,实际值为 111,说明 xxx 的所有儿子,必须满足理论值为 111,且至少一个实际值不为 111
容易想到容斥原理,易得 DPx,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1 等于:所有儿子的理论值都为 111,实际值随意的情况数,减去所有儿子理论值都为 111 ,实际值都为 111 的情况数。
又因为所有儿子理论值都为 111 ,实际值都为 111 的情况数等于 DPx,0,0\operatorname{DP}_{x, 0, 0}DPx,0,0,所以有转移方程:
DPx,0,1=∏i是x的儿子(DPi,1,0+DPi,1,1)−DPx,0,0\operatorname{DP}_{x, 0, 1}=\prod_{\text{i是x的儿子}}(\operatorname{DP}_{i, 1, 0} +\operatorname{DP}_{i, 1, 1} )-\operatorname{DP}_{x, 0, 0} DPx,0,1=i是x的儿子∏(DPi,1,0+DPi,1,1)−DPx,0,0
DPx,1,0\operatorname{DP}_{x, 1, 0}DPx,1,0 的转移
与 DPx,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1 类似,可以得到转移方程:
DPx,1,0=∏i是x的儿子(DPi,0,1+DPi,1,1)−DPx,0,0\operatorname{DP}_{x, 1, 0}=\prod_{\text{i是x的儿子}}(\operatorname{DP}_{i, 0, 1} +\operatorname{DP}_{i, 1, 1} )-\operatorname{DP}_{x, 0, 0} DPx,1,0=i是x的儿子∏(DPi,0,1+DPi,1,1)−DPx,0,0
DPx,1,1\operatorname{DP}_{x, 1, 1}DPx,1,1 的转移
由于 DPx,0,0\operatorname{DP}_{x, 0, 0}DPx,0,0,DPx,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1,DPx,1,0\operatorname{DP}_{x, 1, 0}DPx,1,0,DPx,1,1\operatorname{DP}_{x, 1, 1}DPx,1,1 四种情况为所有的状态,所以只需要用所有的状态减去前面三个状态,就可以得到 DPx,1,1\operatorname{DP}_{x, 1, 1}DPx,1,1 了,即:
DPx,1,1=2cnt[x]⋅∏i是x的儿子(DPi,0,0+DPi,0,1+DPi,1,0+DPi,1,1)−(DPx,0,0+DPx,0,1+DPx,1,0)\operatorname{DP}_{x, 1, 1}=2^{\operatorname{cnt}[x]}\cdot \prod_{\text{i是x的儿子}}(\operatorname{DP}_{i, 0, 0}+\operatorname{DP}_{i, 0, 1}+\operatorname{DP}_{i, 1, 0}+\operatorname{DP}_{i, 1, 1})-(\operatorname{DP}_{x, 0, 0}+\operatorname{DP}_{x, 0, 1}+\operatorname{DP}_{x, 1, 0}) DPx,1,1=2cnt[x]⋅i是x的儿子∏(DPi,0,0+DPi,0,1+DPi,1,0+DPi,1,1)−(DPx,0,0+DPx,0,1+DPx,1,0)
至此,我们已经知道了:若 xxx 不是一个坏了的与非门,如何从 xxx 的儿子转移到 xxx 上。
void dfs(int x) {dp[x][0][0] = dp[x][0][1] = dp[x][1][0] = 1;dp[x][1][1] = power(2, cnt[x]);for(int i = head[x]; i; i = edge[i].nxt) {int ne = edge[i].to;dfs(ne);dp[x][0][0] *= dp[ne][1][1];dp[x][0][1] *= dp[ne][1][0] + dp[ne][1][1];dp[x][1][0] *= dp[ne][0][1] + dp[ne][1][1];dp[x][1][1] *= dp[ne][0][0] + dp[ne][0][1] + dp[ne][1][0] + dp[ne][1][1];}dp[x][0][1] -= dp[x][0][0];dp[x][1][0] -= dp[x][0][0];dp[x][1][1] -= dp[x][0][0] + dp[x][0][1] + dp[x][1][0];
}
Part\rm{Part}Part 2\rm{2}2
下面处理特殊情况:xxx 是坏了的与非门。
如果 xxx 只能输出 000,不能输出 111.
因为 Part\rm{Part}Part 1\rm{1}1 中的实际值,是在默认 xxx 不是坏了的与非门的前提下考虑的。如果 xxx 是坏了的与非门,那么 DPx\operatorname{DP}_{x}DPx 就只与 xxx 儿子的理论值相关了。
所以 Part\rm{Part}Part 1\rm{1}1 中的 DPx,1,1\operatorname{DP}_{x, 1, 1}DPx,1,1 应该归到 DPx,1,0\operatorname{DP}_{x, 1, 0}DPx,1,0 中,DPx,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1 应该归到 DPx,0,0\operatorname{DP}_{x, 0, 0}DPx,0,0 中,即:
if(t[now].sta == 0) {dp[now][0][0] += dp[now][0][1];dp[now][1][0] += dp[now][1][1];dp[now][0][1] = dp[now][1][1] = 0;
}
如果 xxx 只能输出 111,不能输出 000.
同理,将 Part\rm{Part}Part 1\rm{1}1 中的 DPx,0,0\operatorname{DP}_{x, 0, 0}DPx,0,0 应该归到 DPx,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1 中,DPx,1,0\operatorname{DP}_{x, 1, 0}DPx,1,0 应该归到 DPx,1,1\operatorname{DP}_{x, 1, 1}DPx,1,1 中.
if(t[now].sta == 1) {dp[now][0][1] += dp[now][0][0];dp[now][1][1] += dp[now][1][0];dp[now][0][0] = dp[now][1][0] = 0;
}
代码
代码没开long long,没取模(因为加上取模之后代码宽度直接爆炸)
#include <bits/stdc++.h>
#define MAXN 200008
using namespace std;
int n, root;
struct Point{int fa, cnt_son, sta;} t[MAXN];
struct Edge{int to, nxt;} edge[2 * MAXN];
int head[MAXN], cnt = 0;
int deg[MAXN], res[MAXN];
void add(int x, int y) {edge[++cnt].to = y;edge[cnt].nxt = head[x];head[x] = cnt;deg[x]++;
}
int dp[MAXN][2][2];
int power(int x, int k) {int ret = 1;while(k) {if(k & 1) ret = ret * x;k >>= 1;x = x * x;}return ret;
}
int inv(int x, int p) {return power(x, p - 2) % p;
}
void dfs(int now) {res[now] = t[now].cnt_son - deg[now];dp[now][0][0] = dp[now][0][1] = dp[now][1][0] = 1;dp[now][1][1] = power(2, res[now]);for(int i = head[now]; i; i = edge[i].nxt) {int ne = edge[i].to;dfs(ne);res[now] += res[ne];dp[now][0][0] *= dp[ne][1][1];dp[now][0][1] *= dp[ne][1][0] + dp[ne][1][1];dp[now][1][0] *= dp[ne][0][1] + dp[ne][1][1];dp[now][1][1] *= dp[ne][0][0] + dp[ne][0][1] + dp[ne][1][0] + dp[ne][1][1];}dp[now][0][1] -= dp[now][0][0];dp[now][1][0] -= dp[now][0][0];dp[now][1][1] -= dp[now][0][0] + dp[now][0][1] + dp[now][1][0];if(t[now].sta == 0) {dp[now][0][0] += dp[now][0][1];dp[now][1][0] += dp[now][1][1];dp[now][0][1] = dp[now][1][1] = 0;}if(t[now].sta == 1) {dp[now][0][1] += dp[now][0][0];dp[now][1][1] += dp[now][1][0];dp[now][0][0] = dp[now][1][0] = 0;}
}
int main() {cin >> n;for(int i = 1; i <= n; i++) {cin >> t[i].fa >> t[i].cnt_son >> t[i].sta;if(t[i].fa == 0) {root = i;continue;}add(t[i].fa, i);}dfs(root);int ans = (dp[root][0][0] + dp[root][1][1]) * inv(power(2, res[root]), 998244353);cout << ans << endl;return 0;
}
ZROI – 19普及组 – Day2 – T4 – 与非门树相关推荐
- P1047 [NOIP2005 普及组] 校门外的树(python3实现)
[NOIP2005 普及组] 校门外的树 - 洛谷 """P1047 [NOIP2005 普及组] 校门外的树(python3实现) https://www.luogu. ...
- 信息学奥赛一本通 1107:校门外的树 | 1931:【05NOIP普及组】校门外的树 | OpenJudge NOI 1.6 06 | 洛谷 P1047 [NOIP2005 普及组] 校门外的树
[题目链接] ybt 1107:校门外的树 ybt 1931:[05NOIP普及组]校门外的树 OpenJudge NOI 1.6 06:校门外的树 洛谷 P1047 [NOIP2005 普及组] 校 ...
- 【2015NOIP普及组】T4:推销员 试题解析
[15NOIP普及组]推销员 时间限制: 1000 ms 内存限制: 131072 KB [题目描述] 阿明是一名推销员,他奉命到螺丝街推销他们公司的产品.螺丝街是一条死胡同,出口与入 ...
- 洛谷P1047 [NOIP2005 普及组] 校门外的树
题目描述 某校大门外长度为 ll 的马路上有一排树,每两棵相邻的树之间的间隔都是 11 米.我们可以把马路看成一个数轴,马路的一端在数轴 00 的位置,另一端在 ll 的位置:数轴上的每个整数点,即 ...
- 【2016NOIP普及组】T4:魔法阵 试题解析
[16NOIP普及组]魔法阵 时间限制: 1000 ms 内存限制: 262144 KB [题目描述] 六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法量. 大魔法 ...
- 【NOIp普及组2004】FBI树
题目描述 ** 我们可以把由"0"和"1"组成的字符串分为三类:全"0"串称为B串,全"1"串称为I串,既含" ...
- CSP-J2019普及组复赛T4:加工零件
题目描述 凯凯的工厂正在有条不紊地生产一种神奇的零件,神奇的零件的生产过程自然也很神奇. 工厂里有 n n n 位工人,工人们从 1 1 1∼ n n
- 【2019CSP-J普及组】T4 加工零件
P5663 加工零件 题目传送门 SPFA对于每个点是可多次出队入队的,so数组要开大些(检查40分钟 2个WA) 思路: 举个栗子: 7号工人做一个第5个阶段的零件,1号工人是否要做原材料? 可以看 ...
- 【2020.10.30 洛谷团队赛 普及组】T4 U138096 租车去春游
题目描述 M小学组织小朋友们去春游,一共有n个小朋友参加这次集体活动,他们需要走 s 米的路程才能到达 目的地.每个学生的行走速度是 v1,为了减少在路程上消耗的时间,学校决定租一辆公交车,公交车 的 ...
最新文章
- java中局部变量和成员变量_Java中局部变量和成员变量可以转换么?
- MyEclipse图表工具Birt的使用技巧(三)--连接webservice数据源
- 利用NPP-VIIRS夜光数据识别中国收缩城市
- 配置Exchange 2007边缘同步
- Spring和石英:多作业计划服务
- Vue页面骨架屏(一)
- uniapp 微信小程序打包发布
- 开发经验分享_05_葫芦画瓢
- linux 进程函数替换,Linux使用exec函数实现进程替换的代码分享
- Linux系统NFS什么意思,挂载NFS到底是什么概念
- BLE4.0教程四 新增特征值(CC2541)
- KL散度的通俗易懂理解
- CentOS6上安装Flash Player
- Python 的解释器
- centos 6.4 使用sendmail发送邮件(cacti)
- 手机浏览器打开微信小程序,支持外部浏览器跳转到小程序
- 视频添加背景音乐ffmpeg(十八)
- C语言lowB排序和NB排序
- 用字节数组存放二维地图数据
- TokenInsight 对话首席——智能法律合约,去中心化的法务、仲裁之路可否行通
热门文章
- 小程序项目:基于微信小程序的科普之家小程序—计算机毕业设计
- 战地2服务器主程序修改,战地2BOT数值怎么更改BOT数值如何更改_BOT数值更改教程_游戏城...
- ubuntu16.04更新系统后桌面出错的解决办法
- IPO (Python)
- 【原理+实战+视频+源码】抖音,快手大热背后——Android 贴心的音视频学习指南来咯!
- 【论文写作】有了这些网站,可以解决论文写作中99.9%的问题!
- Excel表格 |两列数据(多列)合并一列且自动换行
- Javaweb 成语接龙(实验)
- 公式编辑器如何使用详细图解
- 【Linux修炼】6.gcc/g++及Makefile【工具篇】