首页 > 其他分享 >ARC130D ZigZag Tree 题解

ARC130D ZigZag Tree 题解

时间:2023-04-08 13:11:07浏览次数:55  
标签:sz ARC130D int 题解 Tree times binom include dp

题目链接
考虑这棵树在满足条件下是什么样子的?

Picture 1

我们发现如果对于一棵树黑白染色,白色表示周围的点大于自身,黑色的点反之,是满足条件的。同时,将黑白点反色也是满足条件的。

我们考虑进行 \(\text{dp}\) ,设 \(dp_{i,j,0/1}\) 表示以点 \(i\) 为根的子树,\(i\) 点权值的排名是 \(j\) ,且 \(i\) 点颜色是黑或白的方案数。

Picture 2

以 \(x\) 点为白点为例,考虑将子树 \(v\) 合并到 \(x\) 的过程中前 \(t\) 个点插入到了 \(x\) 前,剩余的 \(sz[v] - t\) 个点在 \(x\) 后。那么此时转移为

\[dp[x][i+t][1] += \binom{i-1+t}{t} \binom{sz[x]-i+sz[v]-t}{sz[v]-t} \times dp[x][i][1] \times dp[v][j][0] (t \geq j) \]

对于 \(x\) 点是黑点的转移同理为

\[dp[x][i+t][0] += \binom{i-1+t}{t} \binom{sz[x]-i+sz[v]-t}{sz[v]-t} \times dp[x][i][0] \times dp[v][j][1] (t \leq j-1) \]

此时 \(dp\) 的转移复杂度为 \(O(n^3)\) ,无法通过。

考虑枚举 \(t\) 算所有能转移到 \(t\) 的 \(j\) 的贡献,式子改写为

\[dp[x][i+j][1] += \binom{i-1+j}{j} \binom{sz[x]-i+sz[v]-j}{sz[v]-j} \times dp[x][i][1] \times pre[j] \]

\[dp[x][i+j][0] += \binom{i-1+j}{j} \binom{sz[x]-i+sz[v]-j}{sz[v]-j} \times dp[x][i][0] \times suc[j+1] \]

其中

\[pre[j]= \sum_{k=1}^{j} dp[v][k][0] \]

\[suc[j]= \sum_{k=j+1}^{sz[v]} dp[v][k][1] \]

复杂度为 \(O(n^2)\) ,可以通过。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int N=3005;
struct node{
	int nxt;int to;
}e[N*2];
int head[N],tot;
int n,rx,ry;
int fa[N],sz[N];
int dp[N][N][2],pre[N],suc[N];
int g[N][2],ans;
int fac[N],ifac[N];
inline void read(int &x) 
{
	int f=1;char c;
	for(x=0,c=getchar();c<'0'||c>'9';c=getchar()) if(c=='-') f=-1;
	for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48); x*=f;
} 
inline int mn(int _x,int _y){return _x<_y?_x:_y;}
inline int mx(int _x,int _y){return _x>_y?_x:_y;}
inline int ab(int _x){return _x<0?-_x:_x;}
inline void add(int from,int to){
	e[++tot].to=to;e[tot].nxt=head[from];head[from]=tot;
}
inline int C(int n,int m){
	if(n<m) return 0;
	return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
inline int qpow(int base,int cnt){
	int rest=1;
	while(cnt){
		if(cnt&1) rest=1ll*rest*base%mod;
		base=1ll*base*base%mod;
		cnt>>=1;
	}
	return rest;
}
inline void dfs(int x){
	sz[x]=1;
	dp[x][1][0]=dp[x][1][1]=1;
	for(int ei=head[x];ei;ei=e[ei].nxt){
		int v=e[ei].to;
		if(v==fa[x]) continue;
		fa[v]=x;dfs(v);
		for(int j=0;j<=sz[v]+1;j++) pre[j]=suc[j]=0;
		for(int j=1;j<=sz[v];j++) pre[j]=(pre[j-1]+dp[v][j][0])%mod;
		for(int j=sz[v];j>=1;j--) suc[j]=(suc[j+1]+dp[v][j][1])%mod;
		for(int i=1;i<=sz[x];i++){
			for(int j=0;j<=sz[v];j++){
				g[i+j][0]=(g[i+j][0]+1ll*C(i-1+j,j)*C(sz[x]-i+sz[v]-j,sz[v]-j)%mod*dp[x][i][0]%mod*suc[j+1]%mod)%mod;
				g[i+j][1]=(g[i+j][1]+1ll*C(i-1+j,j)*C(sz[x]-i+sz[v]-j,sz[v]-j)%mod*dp[x][i][1]%mod*pre[j]%mod)%mod;
			}
		}
		sz[x]+=sz[v];
		for(int i=0;i<=sz[x];i++){
			dp[x][i][0]=g[i][0];dp[x][i][1]=g[i][1];
			g[i][0]=g[i][1]=0;
		}
	}
//	for(int i=1;i<=sz[x];i++) printf("dp[%d][%d] [0]=%d [1]=%d\n",x,i,dp[x][i][0],dp[x][i][1]);
	return ;
}
int main()
{
	read(n);
	for(int i=1;i<n;i++){
		read(rx);read(ry);
		add(rx,ry);add(ry,rx);
	}
	fac[0]=1;for(int i=1;i<=n+1;i++) fac[i]=1ll*i*fac[i-1]%mod;
	ifac[n+1]=qpow(fac[n+1],mod-2);
	for(int i=n;i>=0;i--) ifac[i]=1ll*(i+1)*ifac[i+1]%mod;

	dfs(1);
	for(int i=1;i<=n;i++){
		ans=(ans+dp[1][i][0])%mod;
		ans=(ans+dp[1][i][1])%mod;
	}
	printf("%d\n",ans);
	return 0;
}  

标签:sz,ARC130D,int,题解,Tree,times,binom,include,dp
From: https://www.cnblogs.com/FireAspect/p/17298350.html

相关文章

  • 【牛客小白月赛70】A-F题解【小d和超级泡泡堂】【小d和孤独的区间】【小d的博弈】【小
    比赛传送门:https://ac.nowcoder.com/acm/contest/53366难度适中。......
  • Edu Round 板刷计划 4. Educational Codeforces Round 4 题解
    ChangeLog:2023.04.06开坑.A-TheTextSplitting弱智题.枚举分出来多少个长度为\(p\)的串,则能计算出长度为\(q\)的串有多少个,若合法则直接输出即可.无解输出-1.Samplesubmission.B-HDDisOutdatedTechnology比A还弱智.直接记录每个数的位置,然后模拟一......
  • [ARC127D] Sum of Min of Xor 题解
    先把\(i\)对\(j\)的约束去掉。没有\(\min\)的情况是trival的,发现瓶颈在于如何比较两个数之间的大小。可以发现,对两个二进制数,我们本质上是想要找到它们第一个不同的位置。于是考虑从最高位开始,将\((a_i,b_i)\)按最高位分组为\((0,0),(0,1),(1,0),(1,1)\)四组。每组内......
  • 【题解】P4898 [IOI2018] seats 排座位
    思路线段树。题意可以转化成每次判定有多少个前缀满足所有结点构成矩形。首先排除确定矩阵坐标再数答案的做法,因为太难。所以考虑如何对前缀进行判定。一个简单的想法是维护前\(i\)个点中\(x,y\)坐标的最值,但这样只能暴力看矩阵中的所有元素,跑得很慢。不妨思考一下合法......
  • 【题解】CF472G Design Tutorial: Increase the Constraints
    《正解分块+FFT跑1min,__builtin_popcount暴力跑10s》《没人写正解,CF也不卡》思路正解:分块+FFT乱搞:__builtin_popcount首先我们知道哈明距离可以用一种\(O(|字符集||S|)\)的算法求。具体考虑枚举字符集中的每一个字符,将两个串中是该字符的位置看作\(1\),不是该字......
  • 【题解】臭气弹
    用次数乘上\(P/Q\)来构建增广矩阵,进行高斯消元。在算出每个点被摧毁的概率与所有点的期望出现次数。由于每个点爆炸概率相同,所以每个点被摧毁的概率就是这个点的期望出现次数\(/\)所有点的期望出现次数。#include<bits/stdc++.h>usingnamespacestd;constintN=311;......
  • 荣耀magicbook安装Linux系统boot fail问题解决
    偶然网上冲浪,发现了Debian系的kalilinux有点意思,刚好手边有一台不怎么用的荣耀magicbook,于是准备装个双系统好不容易下完了kali的镜像,使rufus写入了U盘但是在安装过程中怎么安装都显示bootfail,切换了n个版本的Linux系统,发现还是这样,但是实测Debian11是可以进入引导项的最后所......
  • CF1810E 题解
    一、题目描述:给你一个n个点,m条边的无向图,点带权,起点可任意选择。每走过一个新的点,你的能力值会+1。一开始你的能力值为0。你只能经过点权小于等于你能力值的点。每条边,每个点都可以经过无限次,问能否走遍整个图。如果可以,输出"YES"。否则输出"NO"。......
  • POJ - 2029 Get Many Persimmon Trees(暴力水题)
    题目大意:给你一个矩阵,矩阵上面有N个柿子树,现在要求你画一个s*t的矩阵,使得这个矩阵内的柿子树达到最多解题思路:100*100,直接暴力#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;constintN=110;intn,w,h,s,t;intmap[N][N];voidin......
  • B-tree
    在计算机科学中,B树(英语:B-tree)是一种自平衡的树,能够保持数据有序。这种数据结构能够让查找数据、顺序访问、插入数据及删除的动作,都在对数时间内完成。B树,概括来说是一个一般化的二叉查找树(binarysearchtree),可以拥有多于2个子节点。与自平衡二叉查找树不同,B树为系统大块数据的读......