_{^{_{谨以此文表达笔者个人观点,如有冒犯官解,可在评论区诉说}}}

谨以此文表达笔者个人观点,如有冒犯官解,可在评论区诉说​​

题面

原题

天体风暴中的气象瞬息万变。

风暴中的道路构成一棵

n

n

n 个结点的无根树,第

i

i

i 个结点有初始权值

w

i

w_i

wi​(

w

i

w_i

wi​ 为

0

0

0 或

1

1

1)和类型

t

i

t_i

ti​。

结点的类型分为两种:

AND

\texttt{AND}

AND 型结点和

OR

\texttt{OR}

OR 型结点。

对于

AND

\texttt{AND}

AND 型结点,每一秒结束后它的权值将变为它与它所有邻居上一秒权值的

AND

\texttt{AND}

AND 和

对于

OR

\texttt{OR}

OR 型结点,每一秒结束后它的权值将变为它与它所有邻居上一秒权值的

OR

\texttt{OR}

OR 和

现在,已知从某一时刻起,所有结点的权值都不再发生任何变化,将此时点

i

i

i 的权值称为

a

i

a_i

ai​。

现不知每个点的初始权值和类型,只知道最终每个点的权值

a

i

a_i

ai​,求出有多少种可能的初始权值和类型的组合,答案对

998244353

998244353

998244353 取模。

2

n

2

×

1

0

5

,

1000

m

s

,

256

M

B

2\leq n\leq2\times10^5~~,~~1000\,{\tt ms}~~,~~256\,{\tt MB}

2≤n≤2×105  ,  1000ms  ,  256MB .

题解

我们可以发现,

A

N

D

\tt AND

AND 类型一但接触到 0,就会保持 0 永久不变,

O

R

\tt OR

OR 类型一旦接触到 1,就会保持 1 永久不变。所以,最终的情况,一定是由权值为 1 的

O

R

\tt OR

OR 、权值为 0 的

A

N

D

\tt AND

AND 、四周全是 1 的

A

N

D

\tt AND

AND 和 四周全是 0 的

O

R

\tt OR

OR 组成。

我讲的尽量形象一点吧。


我们先看 0 和 1 的交界处,它们比较特别。

这些地方能一直保持这种 “剑拔弩张” 的状态,想必交界处的两个点不简单。简单假设推理一下就会发现,边界处的 1 一定是

O

R

\tt OR

OR 形,因为它们是 “亲 1” 的,能守其 1,义不变 0,如果是

A

N

D

\tt AND

AND 形就守不住 1 了,和紧挨着的 0 只用接触一回合,就永远变成 0 了。同理,0 那边一定是

A

N

D

\tt AND

AND 形的 0 了。

我们不妨把这两种结点称之为 “哨兵”,每一个 1 的连通块、或者 0 的连通块边上(边上指的是0,1交界处)都必须有哨兵把守。当然,这并不代表连通块内部就没有哨兵了。

类似的,1-连通块内的

A

N

D

\tt AND

AND 、0-连通块内的

O

R

\tt OR

OR 这两种朝三暮四的结点,不妨把它们称之为 “庶民” 。

一开始,并不一定每个哨兵都是自己应该的权值(1-连通块内为 1,0-连通块内为 0),它们可能 “未激活”(呈现为敌方的权值),一个未激活的哨兵是可以被身边的 “亲和权值” 给感染、然后激活的,这其中包括身边的激活的友方哨兵(出于呼唤)或未激活的敌方哨兵(出于警觉)。

但是,庶民的摇摆不定就决定了,任何时刻,庶民和 “敌对势力” 或者未激活的友方哨兵(毕竟带有敌方的权值)中间都必须有激活的哨兵相隔。


这么想,那么最初就可能是这样:每个连通块内有若干个小块,这些小块周围是一圈激活的哨兵,内部是哨兵或庶民,连通块内除了这些小块以外的地方,全是未激活的哨兵。随着时间推移,未激活的哨兵渐渐全部激活,最终形成输入中的模样。

但对于每个连通块,还有一种情况:一开始就全是未激活的哨兵!庶民不识抬举,要他们何用 这种情况,连通块四周一定得有至少一个敌方的未激活哨兵相邻才行,不然会被围剿死 不然就全都激活不了了。


好,接下来,就可以着手设计 DP 了。

同权值的连通块一开始是已知的。每个点最初的状态有三种 :未激活的哨兵,激活的哨兵,庶民。分别用 1,2,3 型表示吧,我们设计

d

p

1

[

i

]

dp1[i]

dp1[i],

d

p

2

[

i

]

dp2[i]

dp2[i],

d

p

3

[

i

]

dp3[i]

dp3[i] 表示结点

i

i

i 先不考虑父亲的情况下为 1、2、3 型时,

i

i

i 子树的方案数。

但是对于一开始就全是未激活哨兵的情况不好处理,于是我们就令

d

p

1

[

i

]

[

1

]

dp1[i][1]

dp1[i][1] 为原先的

d

p

1

[

i

]

dp1[i]

dp1[i] ,令

d

p

1

[

i

]

[

0

]

dp1[i][0]

dp1[i][0] 为

i

i

i 结点所在连通块(暂不考虑其父亲)全是未激活哨兵、并被围剿死的情况下,子树的方案数,也就是不合法的方案数。

这四者初始值都为 1,因为要做乘法。最后

d

p

1

[

i

]

[

1

]

dp1[i][1]

dp1[i][1] 要减去

d

p

1

[

i

]

[

0

]

dp1[i][0]

dp1[i][0] ,即减去不合法。

如果扫描到某个儿子

j

j

j,与自己在同一个连通块内(

a

i

=

a

j

a_i=a_j

ai​=aj​),那么:

  • d

    p

    1

    [

    i

    ]

    [

    0

    ]

    d

    p

    1

    [

    i

    ]

    [

    0

    ]

    d

    p

    1

    [

    j

    ]

    [

    0

    ]

    dp1[i][0]\leftarrow dp1[i][0]*dp1[j][0]

    dp1[i][0]←dp1[i][0]∗dp1[j][0] ,这个很明显,儿子也得被围剿才行。

  • d

    p

    1

    [

    i

    ]

    [

    1

    ]

    d

    p

    1

    [

    i

    ]

    [

    1

    ]

    (

    d

    p

    1

    [

    j

    ]

    [

    0

    ]

    +

    d

    p

    1

    [

    j

    ]

    [

    1

    ]

    +

    d

    p

    2

    [

    j

    ]

    )

    dp1[i][1]\leftarrow dp1[i][1]*(dp1[j][0]+dp1[j][1]+dp2[j])

    dp1[i][1]←dp1[i][1]∗(dp1[j][0]+dp1[j][1]+dp2[j]) ,这是还未减去不合法情况下的

    d

    p

    1

    [

    i

    ]

    [

    1

    ]

    dp1[i][1]

    dp1[i][1] ,所以当然要兼容并包,同时未激活的哨兵可以紧挨着激活的哨兵,所以要算上

    d

    p

    2

    [

    j

    ]

    dp2[j]

    dp2[j] 。

  • d

    p

    2

    [

    i

    ]

    d

    p

    2

    [

    i

    ]

    (

    d

    p

    1

    [

    j

    ]

    [

    0

    ]

    +

    d

    p

    1

    [

    j

    ]

    [

    1

    ]

    +

    d

    p

    2

    [

    j

    ]

    +

    d

    p

    3

    [

    j

    ]

    )

    dp2[i]\leftarrow dp2[i]*(dp1[j][0]+dp1[j][1]+dp2[j]+dp3[j])

    dp2[i]←dp2[i]∗(dp1[j][0]+dp1[j][1]+dp2[j]+dp3[j]) ,已经激活的哨兵在连通块内,说明不符合“全是未激活哨兵” 这种假设了,儿子认为的被围剿死的方案 (

    d

    p

    1

    [

    j

    ]

    [

    0

    ]

    dp1[j][0]

    dp1[j][0]),到父亲这儿又行了。同时,激活的哨兵身边什么人都可以有,自然就全盘转移过来。

  • d

    p

    3

    [

    i

    ]

    d

    p

    3

    [

    i

    ]

    (

    d

    p

    2

    [

    j

    ]

    +

    d

    p

    3

    [

    j

    ]

    )

    dp3[i]\leftarrow dp3[i]*(dp2[j]+dp3[j])

    dp3[i]←dp3[i]∗(dp2[j]+dp3[j]) ,庶民身边只能是庶民或激活的哨兵,这个不必细说。

如果扫描到某个儿子

j

j

j 与自己在不同连通块的话(

a

i

a

j

a_i\not=a_j

ai​​=aj​):

  • d

    p

    1

    [

    i

    ]

    [

    0

    ]

    d

    p

    1

    [

    i

    ]

    [

    0

    ]

    d

    p

    2

    [

    j

    ]

    dp1[i][0]\leftarrow dp1[i][0]*dp2[j]

    dp1[i][0]←dp1[i][0]∗dp2[j] ,既然被对方围剿,那就是和激活的敌方哨兵相邻了。

  • d

    p

    1

    [

    i

    ]

    [

    1

    ]

    d

    p

    1

    [

    i

    ]

    [

    1

    ]

    (

    d

    p

    1

    [

    j

    ]

    [

    0

    ]

    +

    d

    p

    1

    [

    j

    ]

    [

    1

    ]

    +

    d

    p

    2

    [

    j

    ]

    )

    dp1[i][1]\leftarrow dp1[i][1]*(dp1[j][0]+dp1[j][1]+dp2[j])

    dp1[i][1]←dp1[i][1]∗(dp1[j][0]+dp1[j][1]+dp2[j]) ,对方可以是激活或未激活的哨兵,这个不用说。主要是

    d

    p

    1

    [

    j

    ]

    [

    0

    ]

    dp1[j][0]

    dp1[j][0] ,由于父亲是未激活的哨兵,儿子认为的被围剿死的方案,因父亲放了生路,又行了。

  • d

    p

    2

    [

    i

    ]

    d

    p

    2

    [

    i

    ]

    (

    d

    p

    1

    [

    j

    ]

    [

    1

    ]

    +

    d

    p

    2

    [

    j

    ]

    )

    dp2[i]\leftarrow dp2[i]*(dp1[j][1]+dp2[j])

    dp2[i]←dp2[i]∗(dp1[j][1]+dp2[j]) ,激活的哨兵,儿子被围剿就是被围剿,和上面相比,不能转移过来。

  • d

    p

    3

    [

    i

    ]

    0

    dp3[i]\leftarrow 0

    dp3[i]←0 ,庶民怎么能跑到边境呢?直接清零。

最后再来一个

d

p

1

[

i

]

[

1

]

(

d

p

1

[

i

]

[

1

]

d

p

1

[

i

]

[

0

]

)

dp1[i][1]\leftarrow (dp1[i][1]-dp1[i][0])

dp1[i][1]←(dp1[i][1]−dp1[i][0]) 。

至此,转移就理清了,最终答案是

d

p

1

[

R

o

o

t

]

[

1

]

+

d

p

2

[

R

o

o

t

]

+

d

p

3

[

R

o

o

t

]

dp1[Root][1]+dp2[Root]+dp3[Root]

dp1[Root][1]+dp2[Root]+dp3[Root]。时间复杂度

O

(

n

)

O(n)

O(n) 。

CODE

精炼的代码

#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define ENDL putchar('\n')
#define LL long long
#define DB double
#define lowbit(x) ((-x) & (x))
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
const int MOD = 998244353;
int n,m,i,j,s,o,k;
vector<int> g[MAXN];
int inv[MAXN];
int a[MAXN];
int dp1[MAXN][2],dp2[MAXN],dp3[MAXN]; // 1,2,3
void dfs(int x,int ff) {
dp1[x][0] = dp2[x] = dp3[x] = 1;
dp1[x][1] = 1;
for(int i = 0;i < (int)g[x].size();i ++) {
int y = g[x][i];
if(y != ff) {
dfs(y,x);
if(a[y] == a[x]) {
dp1[x][1] = (0ll+dp1[y][0] + dp1[y][1] + dp2[y]) % MOD *1ll* dp1[x][1] % MOD;
dp1[x][0] = dp1[y][0] *1ll* dp1[x][0] % MOD;
dp2[x] = (0ll+dp1[y][0]+dp1[y][1] + dp3[y] + dp2[y]) % MOD *1ll* dp2[x] % MOD;
dp3[x] = (dp2[y] + dp3[y]) % MOD *1ll* dp3[x] % MOD;
}
else {
dp1[x][1] = (0ll+dp1[y][1] + dp1[y][0] + dp2[y]) % MOD *1ll* dp1[x][1] % MOD;
dp1[x][0] = (dp2[y]) % MOD *1ll* dp1[x][0] % MOD;
dp2[x] = (dp1[y][1] + dp2[y]) % MOD *1ll* dp2[x] % MOD;
dp3[x] = 0;
}
}
}
(dp1[x][1] += MOD-dp1[x][0]) %= MOD;
return ;
}
int main() {
n = read();
for(int i = 1;i <= n;i ++) {
a[i] = read();
}
inv[0] = inv[1] = 1;
for(int i = 2;i <= n;i ++) {
inv[i] = (MOD-inv[MOD % i]) *1ll* (MOD/i) % MOD;
}
for(int i = 1;i < n;i ++) {
s = read();o = read();
g[s].push_back(o);
g[o].push_back(s);
}
dfs(1,0);
int ans = (0ll+dp1[1][1]+dp2[1]+dp3[1]) % MOD;
printf("%d\n",ans);
return 0;
}

P7727 风暴之眼 Eye of the Storm (树形 DP)的更多相关文章

  1. poj3417 LCA + 树形dp

    Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Descripti ...

  2. COGS 2532. [HZOI 2016]树之美 树形dp

    可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...

  3. 【BZOJ-4726】Sabota? 树形DP

    4726: [POI2017]Sabota? Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 128  Solved ...

  4. 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)

    题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...

  5. 树形DP

    切题ing!!!!! HDU  2196 Anniversary party 经典树形DP,以前写的太搓了,终于学会简单写法了.... #include <iostream> #inclu ...

  6. BZOJ 2286 消耗战 (虚树+树形DP)

    给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...

  7. POJ2342 树形dp

    原题:http://poj.org/problem?id=2342 树形dp入门题. 我们让dp[i][0]表示第i个人不去,dp[i][1]表示第i个人去 ,根据题意我们可以很容易的得到如下递推公式 ...

  8. hdu1561 The more, The Better (树形dp+背包)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1561 思路:树形dp+01背包 //看注释可以懂 用vector建树更简单. 代码: #i ...

  9. bzoj2500: 幸福的道路(树形dp+单调队列)

    好题.. 先找出每个节点的树上最长路 由树形DP完成 节点x,设其最长路的子节点为y 对于y的最长路,有向上和向下两种情况: down:y向子节点的最长路g[y][0] up:x的次长路的g[x][1 ...

随机推荐

  1. Arraylist集合、对象数组

    Arraylist集合 ArrayList是List接口的一个实现类,它是程序中最常见的一种集合. 他的特点:在增加或删除指定位置的元素时,会创建新的数组,效率比较低,因此不适合做大量的增删操作,Ar ...

  2. [WUSTCTF2020]颜值成绩查询-1

    分享下自己在完成[WUSTCTF2020]颜值成绩查询-1关卡的手工过程和自动化脚本. 1.通过payload:1,payload:1 ,payload:1 or 1=1--+,进行判断是否存在注入, ...

  3. 获得MySQL数据库存放位置

    更新记录 2022年6月13日 发布. 2022年6月11日 开始. 通过查看MySQL与存储目录相关的参数 show variables like '%dir%'; 通过查询后datadir参数的值 ...

  4. 【Java面试】TCP协议为什么要设计三次握手?

    一个工作5年的粉丝,最近去面试了很多公司,每次都被各种技术原理题问得语无伦次. 由于找了快1个月时间的工作,有点焦虑,来向我求助. 我能做的只是保证每天更新一个面试题,然后问他印象最深刻的一个面试题是 ...

  5. JavaScript有哪些数据类型,它们的区别?

    基本数据类型:number.string.boolean.Undefined.NaN(特殊值).BigInt.Symbol 引入数据类型:Object NaN是JS中的特殊值,表示非数字,NaN不是数 ...

  6. 一次 Keepalived 高可用的事故,让我重学了一遍它!

    原文首发: 你好,我是悟空. 前言 上次我们遇到了一个 MySQL 故障的事故,这次我又遇到了另外一个奇葩的问题: Keepalived 高可用组件的虚拟 IP 持续漂移,导致 MySQL 主从不断切 ...

  7. SpringBoot 开发案例之整合FastDFS分布式文件系统

    1.pom依赖 <!--fastdfs--> <dependency> <groupId>com.github.tobato</groupId> < ...

  8. Linux系列之文本操作命令

    前言 Linux 有八个常用的文本操作命令:cat.head.tail.nl.grep.sed.more.less.本文介绍它们的区别和简单用法. cat命令 显示文本的最基本命令. cat file ...

  9. Collection子接口:List接口

    1. 存储的数据特点:存储序的.可重复的数据. 2. 常用方法:(记住)增:add(Object obj)删:remove(int index) / remove(Object obj)改:set(i ...

  10. Qt+ECharts开发笔记(二):Qt窗口动态调整大小,使ECharts跟随Qt窗口大小变换而变换大小

    前言   上一篇将ECharts嵌入Qt中,在开始ECharts使用之前,还有一个很重要的功能,就是在窗口变换大小的时候,ECharts的图表尺寸也要跟随Qt窗口变换大小而变换大小.   Demo演示 ...