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

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

题面

原题

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

风暴中的道路构成一棵

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. Camunda定时器事件示例Demo(Timer Events)

    ​Camunda定时器事件(Timer Events)是由定义的计时器触发的事件.它们可以用作启动事件.中间事件或边界事件.边界事件可以中断,也可以不中断. Camunda定时器事件包括:Timer ...

  2. BI与SaaS碰撞,让数据处理更加轻松(下)

    背景 在上篇内容中,我们从SaaS各种功能的角度为大家介绍了在数据处理中SaaS的巨大价值,而本次我们将用实例将为大家展示SaaS与BI间的碰撞又会产生怎样的火花. BI与SaaS集成示例 通常BI分 ...

  3. 【.NET 6】多线程的几种打开方式和代码演示

    前言: 多线程无处不在,平常的开发过程中,应该算是最常用的基础技术之一了.以下通过Thread.ThreadPool.再到Task.Parallel.线程锁.线程取消等方面,一步步进行演示多线程的一些 ...

  4. 使用node.js如何简单快速的搭建一个websocket聊天应用

    初始化项目 npm init 安装nodejs-websocket npm install nodejs-websocket 创建并编辑启动文件 创建一个名为app.js文件,并且编辑它. var w ...

  5. sql-关键词的大小写与注释

    是否区分大小写 和 注释 大小写 oracle 自带的sqlplus: mysql 客户端 : Navicat: 注释 oracle 自带的sqlplus: mysql 客户端 : 小节 oracle ...

  6. C# Winform程序界面优化实例

    进入移动互联网时代以来,Windows桌面开发已经很久不碰了.之前就是从做Windows开发入行的. 当年,还是C++ VC6, MFC的时代.那时候开发要查的是MSDN :-).内存要自己管理, 排 ...

  7. Kafka KRaft模式探索

    1.概述 Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据.其核心组件包含Producer.Broker.Consumer,以及依赖的Zookeeper集群. ...

  8. SpringCloudAlibaba分布式流量控制组件Sentinel实战与源码分析-中

    实战示例 控制台初体验 Sentinel的控制台启动后,控制台页面的内容数据都是空的,接下来我们来逐步操作演示结合控制台的使用,在上一节也已说明整合SpringCloud Alibaba第一步先加入s ...

  9. Java8 Stream 的最佳实践

    Java8 Stream 的最佳实践 java8stream提供了对于集合类的流失处理,其具有以下特点: Lazy Evaluation(长度可以无限) 只能使用一次 内部迭代 Lazy Evalua ...

  10. Static、Final关键字详解

    1.Static 详情见下面代码讲解 点击查看代码 package com.Tang.oop.demo07; public class Student { private static int age ...