题意

给定一棵 nnn 个节点的有根树,每个点有点权。对于所有叶子节点,点权为 000 或 111。非叶子节点分为两类,对于第一类,点权为其所有儿子节点的点权与非和;对于第二类,点权恒为 hi∈[0,1]h_i\in[0, 1]hi​∈[0,1],题目给定 hih_ihi​.

现在给叶子节点赋值。

存在 AAA 种不同的赋值方法使得:若将所有第二类点变为第一类点,根节点的点权不变,一共存在 BBB 种不同的赋值方法。

求 ABmod998244353\frac{A}{B}\bmod 998244353BA​mod998244353.

解法

上面的部分只用于理解题意,与Solution部分基本无关。

考虑树形DP.

定义 cnt⁡[x]\operatorname{cnt}[x]cnt[x] 表示与 xxx 直接相连的叶子节点个数。

定义 xxx 的理论值为:如果所有的与非门都能正常工作,xxx 的点权。

定义 xxx 的实际值为:在实际情况下, xxx 的点权。

设置状态 DP⁡x,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 的儿子转移上来。

DP⁡x,0,0\operatorname{DP}_{x, 0, 0}DPx,0,0​ 的转移

对于 DP⁡x,0,0\operatorname{DP}_{x, 0, 0}DPx,0,0​,理论值和实际值都为 000,所以对于所有 xxx 的儿子,理论值和实际值必须都为 111,即:
DP⁡x,0,0=∏i是x的儿子DP⁡i,1,1\operatorname{DP}_{x, 0, 0} = \prod_{\text{i是x的儿子}}\operatorname{DP}_{i, 1, 1} DPx,0,0​=i是x的儿子∏​DPi,1,1​

DP⁡x,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1​ 的转移

对于 DP⁡x,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1​,理论值为 000,实际值为 111,说明 xxx 的所有儿子,必须满足理论值为 111,且至少一个实际值不为 111

容易想到容斥原理,易得 DP⁡x,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1​ 等于:所有儿子的理论值都为 111,实际值随意的情况数,减去所有儿子理论值都为 111 ,实际值都为 111 的情况数。

又因为所有儿子理论值都为 111 ,实际值都为 111 的情况数等于 DP⁡x,0,0\operatorname{DP}_{x, 0, 0}DPx,0,0​,所以有转移方程:
DP⁡x,0,1=∏i是x的儿子(DP⁡i,1,0+DP⁡i,1,1)−DP⁡x,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​

DP⁡x,1,0\operatorname{DP}_{x, 1, 0}DPx,1,0​ 的转移

与 DP⁡x,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1​ 类似,可以得到转移方程:
DP⁡x,1,0=∏i是x的儿子(DP⁡i,0,1+DP⁡i,1,1)−DP⁡x,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​

DP⁡x,1,1\operatorname{DP}_{x, 1, 1}DPx,1,1​ 的转移

由于 DP⁡x,0,0\operatorname{DP}_{x, 0, 0}DPx,0,0​,DP⁡x,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1​,DP⁡x,1,0\operatorname{DP}_{x, 1, 0}DPx,1,0​,DP⁡x,1,1\operatorname{DP}_{x, 1, 1}DPx,1,1​ 四种情况为所有的状态,所以只需要用所有的状态减去前面三个状态,就可以得到 DP⁡x,1,1\operatorname{DP}_{x, 1, 1}DPx,1,1​ 了,即:
DP⁡x,1,1=2cnt⁡[x]⋅∏i是x的儿子(DP⁡i,0,0+DP⁡i,0,1+DP⁡i,1,0+DP⁡i,1,1)−(DP⁡x,0,0+DP⁡x,0,1+DP⁡x,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 是坏了的与非门,那么 DP⁡x\operatorname{DP}_{x}DPx​ 就只与 xxx 儿子的理论值相关了。

所以 Part\rm{Part}Part 1\rm{1}1 中的 DP⁡x,1,1\operatorname{DP}_{x, 1, 1}DPx,1,1​ 应该归到 DP⁡x,1,0\operatorname{DP}_{x, 1, 0}DPx,1,0​ 中,DP⁡x,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1​ 应该归到 DP⁡x,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 中的 DP⁡x,0,0\operatorname{DP}_{x, 0, 0}DPx,0,0​ 应该归到 DP⁡x,0,1\operatorname{DP}_{x, 0, 1}DPx,0,1​ 中,DP⁡x,1,0\operatorname{DP}_{x, 1, 0}DPx,1,0​ 应该归到 DP⁡x,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 – 与非门树相关推荐

  1. P1047 [NOIP2005 普及组] 校门外的树(python3实现)

    [NOIP2005 普及组] 校门外的树 - 洛谷 """P1047 [NOIP2005 普及组] 校门外的树(python3实现) https://www.luogu. ...

  2. 信息学奥赛一本通 1107:校门外的树 | 1931:【05NOIP普及组】校门外的树 | OpenJudge NOI 1.6 06 | 洛谷 P1047 [NOIP2005 普及组] 校门外的树

    [题目链接] ybt 1107:校门外的树 ybt 1931:[05NOIP普及组]校门外的树 OpenJudge NOI 1.6 06:校门外的树 洛谷 P1047 [NOIP2005 普及组] 校 ...

  3. 【2015NOIP普及组】T4:推销员 试题解析

    [15NOIP普及组]推销员 时间限制: 1000 ms         内存限制: 131072 KB [题目描述] 阿明是一名推销员,他奉命到螺丝街推销他们公司的产品.螺丝街是一条死胡同,出口与入 ...

  4. 洛谷P1047 [NOIP2005 普及组] 校门外的树

    题目描述 某校大门外长度为 ll 的马路上有一排树,每两棵相邻的树之间的间隔都是 11 米.我们可以把马路看成一个数轴,马路的一端在数轴 00 的位置,另一端在 ll 的位置:数轴上的每个整数点,即  ...

  5. 【2016NOIP普及组】T4:魔法阵 试题解析

    [16NOIP普及组]魔法阵 时间限制: 1000 ms         内存限制: 262144 KB [题目描述] 六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法量. 大魔法 ...

  6. 【NOIp普及组2004】FBI树

    题目描述 ** 我们可以把由"0"和"1"组成的字符串分为三类:全"0"串称为B串,全"1"串称为I串,既含" ...

  7. CSP-J2019普及组复赛T4:加工零件

    题目描述 凯凯的工厂正在有条不紊地生产一种神奇的零件,神奇的零件的生产过程自然也很神奇. 工厂里有 n n n 位工人,工人们从 1 1 1∼ n n

  8. 【2019CSP-J普及组】T4 加工零件

    P5663 加工零件 题目传送门 SPFA对于每个点是可多次出队入队的,so数组要开大些(检查40分钟 2个WA) 思路: 举个栗子: 7号工人做一个第5个阶段的零件,1号工人是否要做原材料? 可以看 ...

  9. 【2020.10.30 洛谷团队赛 普及组】T4 U138096 租车去春游

    题目描述 M小学组织小朋友们去春游,一共有n个小朋友参加这次集体活动,他们需要走 s 米的路程才能到达 目的地.每个学生的行走速度是 v1,为了减少在路程上消耗的时间,学校决定租一辆公交车,公交车 的 ...

最新文章

  1. java中局部变量和成员变量_Java中局部变量和成员变量可以转换么?
  2. MyEclipse图表工具Birt的使用技巧(三)--连接webservice数据源
  3. 利用NPP-VIIRS夜光数据识别中国收缩城市
  4. 配置Exchange 2007边缘同步
  5. Spring和石英:多作业计划服务
  6. Vue页面骨架屏(一)
  7. uniapp 微信小程序打包发布
  8. 开发经验分享_05_葫芦画瓢
  9. linux 进程函数替换,Linux使用exec函数实现进程替换的代码分享
  10. Linux系统NFS什么意思,挂载NFS到底是什么概念
  11. BLE4.0教程四 新增特征值(CC2541)
  12. KL散度的通俗易懂理解
  13. CentOS6上安装Flash Player
  14. Python 的解释器
  15. centos 6.4 使用sendmail发送邮件(cacti)
  16. 手机浏览器打开微信小程序,支持外部浏览器跳转到小程序
  17. 视频添加背景音乐ffmpeg(十八)
  18. C语言lowB排序和NB排序
  19. 用字节数组存放二维地图数据
  20. TokenInsight 对话首席——智能法律合约,去中心化的法务、仲裁之路可否行通

热门文章

  1. 小程序项目:基于微信小程序的科普之家小程序—计算机毕业设计
  2. 战地2服务器主程序修改,战地2BOT数值怎么更改BOT数值如何更改_BOT数值更改教程_游戏城...
  3. ubuntu16.04更新系统后桌面出错的解决办法
  4. IPO (Python)
  5. 【原理+实战+视频+源码】抖音,快手大热背后——Android 贴心的音视频学习指南来咯!
  6. 【论文写作】有了这些网站,可以解决论文写作中99.9%的问题!
  7. Excel表格 |两列数据(多列)合并一列且自动换行
  8. Javaweb 成语接龙(实验)
  9. 公式编辑器如何使用详细图解
  10. 【Linux修炼】6.gcc/g++及Makefile【工具篇】