当前位置: 首页 > article >正文

Codeforces Round 926 (Div. 2) D题 Sasha and a Walk in the City(树形dp)

题目链接

Codeforces Round 926 (Div. 2) D题 Sasha and a Walk in the City

思路

题意为计算不存在三点在一条线上的点集的数量。

考虑使用dp。

定义 d p [ i ] [ j ] dp[i][j] dp[i][j]表示以 i i i为根的子树内,从根节点到叶子节点最多经过 j j j选取点。显然, j j j只有为 0 0 0 1 1 1 2 2 2时是合法的。

j = 0 j=0 j=0时, d p [ i ] [ 0 ] dp[i][0] dp[i][0]的答案显然为 1 1 1

j = 1 j = 1 j=1时,最多的情况下便是两条到根的路径合并,最多经过 1 + 1 = 2 1+1=2 1+1=2选取点。所以每一个儿子内可以任意选择。因为可以将 i i i节点这个根选上,所以还要加上没有选取点的方案数。则状态转移方程为: d p [ i ] [ 1 ] = ∏ j ∈ s o n ( i ) ( d p [ j ] [ 0 ] + d p [ j ] [ 1 ] ) dp[i][1] = \prod_{j\in son(i)}^{} (dp[j][0]+dp[j][1]) dp[i][1]=json(i)(dp[j][0]+dp[j][1])

j = 2 j=2 j=2时,由于根到叶子节点最多经过选取点数最大值为 2 2 2,所以只能有一个子树内的dp值可以转移过来。因为根节点可以作为选取点,所以还要加上 1 1 1选取点的方案数。则状态转移方程为: d p [ i ] [ 2 ] = ∑ j ∈ s o n ( i ) ( d p [ j ] [ 1 ] + d p [ j ] [ 2 ] ) dp[i][2] = \sum_{j\in son(i)}^{} (dp[j][1]+dp[j][2]) dp[i][2]=json(i)(dp[j][1]+dp[j][2])

规定 1 1 1为整棵树的根,则最终答案为 d p [ i ] [ 0 ] + d p [ i ] [ 1 ] + d p [ i ] [ 2 ] dp[i][0] + dp[i][1] + dp[i][2] dp[i][0]+dp[i][1]+dp[i][2]

代码

#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e5 + 5, M = 1e6 + 5;
const int mod = 998244353;
const int inf = 0x3f3f3f3f3f3f3f3f;

int n;
int dp[N][3];
vector<int>mp[N];
void dfs(int u, int fu)
{
	dp[u][0] = 1;
	dp[u][1] = 1;
	for (int j : mp[u])
	{
		if (j == fu) continue;
		dfs(j, u);
		dp[u][1] = dp[u][1] * (dp[j][0] + dp[j][1]) % mod;
		dp[u][2] = dp[u][2] + (dp[j][1] + dp[j][2]) % mod;
	}
}
int MOD(int x)
{
	return (x % mod + mod) % mod;
}
void solve()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		mp[i].clear();
		dp[i][0] = dp[i][1] = dp[i][2] = 0;
	}
	for (int i = 1, u, v; i < n; i++)
	{
		cin >> u >> v;
		mp[u].push_back(v);
		mp[v].push_back(u);
	}
	dfs(1, -1);
	int ans = 0;
	for (int i = 0; i <= 2; i++)
		ans = (ans + dp[1][i]) % mod;
	cout << MOD(ans) << endl;
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int test = 1;
	cin >> test;
	for (int i = 1; i <= test; i++)
	{
		solve();
	}
	return 0;
}

http://www.kler.cn/a/350088.html

相关文章:

  • 白玉微瑕:闲谈 SwiftUI 过渡(Transition)动画的“口是心非”(下)
  • 最小距离和与带权最小距离和
  • OpenVela 各模块之间的交互方式和数据流
  • YOLOv8改进,YOLOv8检测头融合DSConv(动态蛇形卷积),并添加小目标检测层(四头检测),适合目标检测、分割等
  • 微前端qiankun的基本使用(vue-element-admin作为项目模版)
  • 2.5G PoE交换机 TL-SE2109P 简单开箱评测,8个2.5G电口+1个10G光口(SFP+)
  • 一起搭WPF架构之数据存入SQL——第一部分
  • Redisson使用全解
  • 微服务与SpringCloud的概述
  • knife4j常用注解
  • 大数据开发电脑千元配置清单
  • SpringBoot项目升级JDK版本(1.8 => 17)
  • Mac电脑使用pyenv管理多版本python环境 _
  • SpringBoot日常:封装redission starter组件
  • 基于Spring Boot的网上点餐系统
  • 【Spring AI】Java实现类似langchain的第三方函数调用_原理与详细示例
  • MLM之Llama-3:Llama 3.2的简介、安装和使用方法、案例应用之详细攻略
  • JIT详解
  • smartctl 设置硬盘的 write-caching
  • fp16与fp32简介与试验
  • 给网站加加速!下一代CDN(EdgeOne/边缘安全加速)使用与配置体验
  • 程序员转行AI 应用赛道太香了!!
  • 什么是分布式锁?Redis的分布式锁又是什么?
  • 深入解析:React中的信号组件与细粒度更新
  • 泰克MDO3054示波器特性和规格Tektronix MSO3054 500M 四通道
  • 【赵渝强老师】Oracle的物理存储结构