2021 ICPC Southeastern Europe Regional Contest Werewolves(树上背包)

链接
题意:给出一个n个节点的树(n≤3000n\le3000n≤3000),每个点有自己的颜色,好子树的定义是,子树内有一半以上的节点是同一种颜色,问有多少种划分子树的方法,最后对998244353998244353998244353取模。
思路:dls讲的树上背包。。当时听了也没太明白代码怎么写,现在想想还是对树上背包这种不太熟。我们对于每个颜色,都要在树上进行一次dp,这样就可以,对于颜色iii,相同看作1,不同是-1,最后统计所有的和大于0的组合方法,所以我们定义数组dp[i][j]dp[i][j]dp[i][j]代表以iii为根,总和为jjj的方案数,正常开成2倍表示负数就行,但是懒得了,就开成dp[i][j][0/1]dp[i][j][0/1]dp[i][j][0/1],0代表负数,1代表正数,最后单独开一个数组代表刚好为0。现在先看转移
①对于uuu的每一个子树vvv(用sumisum_isumi​代表iii号点的和),如果sumu+sumv≤cnt这个颜色的总数sum_u+sum_v\le cnt_{这个颜色的总数}sumu​+sumv​≤cnt这个颜色的总数​那么首先有:dp[u][j+k][1]=dp[u][j+k][1]+ori[u][j][1]∗dp[v][k][1]dp[u][j+k][0]=dp[u][j+k][0]+ori[u][j][0]∗dp[v][k][0]\begin{array}{c} dp[u][j + k][1] = dp[u][j + k][1] + ori[u][j][1] * dp[v][k][1] \\ dp[u][j + k][0] = dp[u][j + k][0] + ori[u][j][0] * dp[v][k][0] \end{array}dp[u][j+k][1]=dp[u][j+k][1]+ori[u][j][1]∗dp[v][k][1]dp[u][j+k][0]=dp[u][j+k][0]+ori[u][j][0]∗dp[v][k][0]​,其中orioriori是这个状态在进行这次转移之前初始状态,正确性是因为,对于一个总和,那他肯定是uuu的总和为jjj的情况和vvv的总和为kkk的情况组合起来。
②对于一个子树vvv,如果sumu≥sumvsum_u \ge sum_vsumu​≥sumv​那么就是,对于一个情况,可以有sumu−sumvsum_u-sum_vsumu​−sumv​,转移方程就为dp[u][j−k][0]=dp[u][j−k][0]+ori[u][j][0]∗dp[v][k][1]dp[u][j−k][1]=dp[u][j−k][1]+ori[u][j][1]∗dp[v][k][0]\begin{array}{c} dp[u][j-k][0] = dp[u][j-k][0] + ori[u][j][0]*dp[v][k][1] \\ dp[u][j-k][1] = dp[u][j-k][1] + ori[u][j][1]*dp[v][k][0] \end{array}dp[u][j−k][0]=dp[u][j−k][0]+ori[u][j][0]∗dp[v][k][1]dp[u][j−k][1]=dp[u][j−k][1]+ori[u][j][1]∗dp[v][k][0]​。
③ 跟②情况刚好相反
④ 两个相减刚好为0,就有转移方程dp0[u]=d[u]+ori[u][j][0]∗dp[v][k][1]+ori[u][j][1]∗dp[v][k][0]dp0[u] = d[u] + ori[u][j][0] * dp[v][k][1] + ori[u][j][1] * dp[v][k][0]dp0[u]=d[u]+ori[u][j][0]∗dp[v][k][1]+ori[u][j][1]∗dp[v][k][0]
⑤对于uuu来说,每次转移最开始,所有的次数都可以从uuu的和为0的状态转移 dp[u][j][0]=dp[u][j][0]+ori0[u]∗dp[v][j][0]dp[u][j][1]=dp[u][j][1]+ori0[u]∗dp[v][j][1]dp0[u]=dp0[u]+ori0[u]∗dp0[v]\begin{array}{c} dp[u][j][0] = dp[u][j][0] + ori0[u] * dp[v][j][0]\\ dp[u][j][1] = dp[u][j][1] + ori0[u] * dp[v][j][1]\\ dp0[u] = dp0[u] + ori0[u] * dp0[v]\end{array}dp[u][j][0]=dp[u][j][0]+ori0[u]∗dp[v][j][0]dp[u][j][1]=dp[u][j][1]+ori0[u]∗dp[v][j][1]dp0[u]=dp0[u]+ori0[u]∗dp0[v]​
所有的情况就讨论完了,但是这样写上去很明显是一个n3n^3n3的算法,所以加上优化,对于每个颜色,记录他的cntcntcnt,如果对于dfs内部的循环,如果他们枚举的和,最大就是m,并且不会超过他节点的总数size,所以每个循环应该小于min(m,size)min(m, size)min(m,size)。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 998244353;
const int N = 3e3+10;
int dp[N][N][2], tmp[N][N][2], d[N], tp[N], ans, val[N], c[N], vis[N], n, m;
int head[N], idx;
struct Edge{int to, nxt;}e[N << 1];
void add(int u, int v) {e[++idx].to = v, e[idx].nxt = head[u], head[u] = idx;}int dfs(int u, int fa)
{int p = 1;if (val[u]) dp[u][1][1] = 1;else dp[u][1][0] = 1;for (int i = head[u]; i; i = e[i].nxt) {int v = e[i].to;if (v == fa) continue;int siz = dfs(v, u);tp[u] = d[u];for (int j = 1; j <= min(p, m); j++) {tmp[u][j][0] = dp[u][j][0];tmp[u][j][1] = dp[u][j][1];}d[u] = (d[u] + d[v] * tp[u]) % MOD;for (int j = 1; j <= min(siz, m); j++) {dp[u][j][0] = (dp[u][j][0] + tp[u] * dp[v][j][0]) % MOD;dp[u][j][1] = (dp[u][j][1] + tp[u] * dp[v][j][1]) % MOD;}for (int j = 1; j <= min(p, m); j++) {dp[u][j][1] = (dp[u][j][1] + tmp[u][j][1] * d[v]) % MOD;dp[u][j][0] = (dp[u][j][0] + tmp[u][j][0] * d[v]) % MOD;for (int k = 1; k <= min(m, siz); k++) {if (k + j <= m) {dp[u][k + j][1] = (dp[u][k + j][1] + tmp[u][j][1] * dp[v][k][1]) % MOD;dp[u][k + j][0] = (dp[u][k + j][0] + tmp[u][j][0] * dp[v][k][0]) % MOD;}if (j - k >= 1) {dp[u][j - k][1] = (dp[u][j - k][1] + tmp[u][j][1] * dp[v][k][0]) % MOD;dp[u][j - k][0] = (dp[u][j - k][0] + tmp[u][j][0] * dp[v][k][1]) % MOD;}if (k - j >= 1) {dp[u][k - j][1] = (dp[u][k - j][1] + tmp[u][j][0] * dp[v][k][1]) % MOD;dp[u][k - j][0] = (dp[u][k - j][0] + tmp[u][j][1] * dp[v][k][0]) % MOD;}if (j == k) {d[u] = (d[u] + tmp[u][j][0] * dp[v][k][1] + tmp[u][j][1] * dp[v][k][0]) % MOD;}}}p += siz;}for (int i = 1; i <= min(p, m); i++) {ans = (ans + dp[u][i][1]) % MOD;}return p;
}signed main()
{cin >> n;for (int i = 1; i <= n; i++) {cin >> c[i];}for (int i = 1; i < n; i++) {int u, v;cin >> u >> v;add(u, v); add(v, u);}for (int i = 1; i <= n; i++) {if (vis[c[i]]) continue;m = 0; vis[c[i]] = 1;for (int j = 1; j <= n; j++) {if (c[i] == c[j]) {m++; val[j] = 1;}else val[j] = 0;}for (int j = 1; j <= n; j++) {d[j] = 0;for (int k = 1; k <= m; k++) {dp[j][k][0] = dp[j][k][1] = 0;}}dfs(1, 0);}cout << ans;return 0;
}

2021 ICPC Southeastern Europe Regional Contest Werewolves(树上背包)相关推荐

  1. 2021 ICPC Southeastern Europe Regional Contest(更新至六题)

    2021 ICPC Southeastern Europe Regional Contest A题签到 A. King of String Comparison 题意:给两个字符串,找出有多少对(l, ...

  2. 2021 ICPC Southeastern Europe Regional Contest ABFGJKLN

    |–>传送门<–| A. King of String Comparison 双指针 给定字符串AAA和BBB,计算满足Asub[l,r]A_{sub[l, r]}Asub[l,r]​字典 ...

  3. 2021 ICPC Southeastern Europe Regional Contest 树上dfs+思维

    |–>传送门<–| 题目大意 给定一颗nnn个节点的树,可以从任意一个点开始dfsdfsdfs,求最小字典序的后续遍历. 题解 首先,对于字典序最小的要求,我们一定是从叶结点中的最小值开始 ...

  4. 【题目记录】——The 2021 ICPC Asia Jinan Regional Contest

    文章目录 C Optimal Strategy 组合数 H Game Coin K Search For Mafuyu 欧拉序列 题目集地址 The 2021 ICPC Asia Jinan Regi ...

  5. ICPC Central Europe Regional Contest 2019 K. K==S(AC自动机+矩阵快速幂)

    Progressive hard octave rock tunes (so-called "phorts") are written using a specifific mus ...

  6. 2020-2021 ICPC Southeastern European Regional Programming Contest (SEERC 2020)

    2020-2021 ICPC Southeastern European Regional Programming Contest (SEERC 2020) B. Reverse Game 题目描述: ...

  7. The 2019 ICPC Asia Shanghai Regional Contest

    The 2019 ICPC Asia Shanghai Regional Contest 题号 题目 知识点 A Mr. Panda and Dominoes B Prefix Code C Maze ...

  8. 2018 ICPC Asia Jakarta Regional Contest

    2018 ICPC Asia Jakarta Regional Contest 题号 题目 知识点 难度 A Edit Distance B Rotating Gear C Smart Thief D ...

  9. The 2021 ICPC Asia Regionals Online Contest (I)

    The 2021 ICPC Asia Regionals Online Contest (I) 写了一晚上,日- 文章目录 一. A Busiest Computing Nodes 二.D Edge ...

最新文章

  1. [微信小程序]物流信息样式加动画效果(源代码附效果图)
  2. EBS通过SQL查找所有的定时请求
  3. Electron中通过globalShortcut实现监听键盘事件进而实现快捷键功能
  4. 游戏的社交与延伸:怎样把玩家连结起来?
  5. 信息网络安全技术知识
  6. java spring redis_spring配置redis(xml+java方式)
  7. [Java基础]反射概述
  8. 函数的调用规则(__cdecl,__stdcall,__fastcall,__pascal)
  9. mysql数据应用从入门_MYSQL数据库应用从入门到精通----读书笔记
  10. c语言递归函数奇偶归一猜想,计算机科学视角下的奇偶归一猜想
  11. 设计模式之责任链模式(Chain of Responsibility )
  12. Android开发:关于高德地图轨迹纠偏,只显示两个点问题的整体概述
  13. IDEA2017破解办法
  14. 用户分层精细化运营-RFM模型-分类模型
  15. 资源调度有什么技术难点?
  16. STM32HAL库微秒延时函数的实现---DWT和SysTick
  17. 白杨SEO:品牌口碑业务指什么?企业品牌口碑如何推广与预防公关危机?
  18. 加拿大海运专线操作流程详解
  19. linux动态链接库全局变量共享问题DLL共享数据段
  20. 2020年全国软件业务收入将破8万亿元

热门文章

  1. Texlive和TeXStudio的下载安装
  2. 推进网络强国建设,筑牢网络安全屏障
  3. 重庆市计算机专业高考试题,职业高中高考计算机专业试卷4
  4. DVWA 之暴力破解攻击(Brute Force)
  5. opencv识别图像红色区域,并输出红色区域中心点坐标
  6. Vue Router 路由中 this.$router 与this.$route区别
  7. Excel数据分析常用函数①——查询函数(vlookup,hlookup,lookup,match,index…)
  8. 彻底禁用停用杀死WIN10的自动更新
  9. 什么是软件模块化,为什么要模块化?
  10. 轻松解决win10不能联网问题