[ARC121E]Directed Tree

Posted Tan_tan_tann

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ARC121E]Directed Tree相关的知识,希望对你有一定的参考价值。

Directed Tree

题解

题目相当于要求 i i i不能在点 i i i的后代的节点上出现。
如果直接求满足所有条件的树的个数是不大好求的,我们可以先将它转化一下,求不满足条件的树的个数。
我们先定义 d p i , j dp_{i,j} dpi,j表示在 i i i的子树上放置了 j j j个不满足条件的点的方案数,容易得到转移方程式
d p u , j = ∑ v ∈ V u ∑ k = 0 j d p u , j − k d p v , k dp_{u,j}=\\sum_{v\\in V_{u}}\\sum_{k=0}^{j}dp_{u,j-k}dp_{v,k} dpu,j=vVuk=0jdpu,jkdpv,k
由于每一对点只会被枚举到一次,所以总的 d p dp dp转移时间复杂度是 O ( n 2 ) O\\left(n^2\\right) O(n2)
答案可以通过容斥求出,
A n s = ∑ i = 0 n ( − 1 ) i d p 1 , i ( n − i ) ! Ans=\\sum_{i=0}^{n}(-1)^idp_{1,i}(n-i)! Ans=i=0n(1)idp1,i(ni)!
乘上 ( n − i ) ! (n-i)! (ni)!代表除了已经不合格的点以外其它点的选择方式,但由于其它点随便选也有可能导致产生更多的点不合格,所以我们要进行容斥。

时间复杂度 O ( n 2 ) O\\left(n^2\\right) O(n2)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 2005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=998244353;
const int zero=500;
const LL jzm=2333;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int n,head[MAXN],tot,dp[MAXN][MAXN],siz[MAXN],tmp[MAXN],fac[MAXN],ans;
struct edge{int to,nxt;}e[MAXN<<1];
void addEdge(int u,int v){e[++tot]=(edge){v,head[u]};head[u]=tot;}
void dosaka(int u,int fa){
	dp[u][0]=1;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;dosaka(v,u);
		for(int j=0;j<=siz[u];j++)
			for(int k=0;k<=siz[v];k++)
				tmp[j+k]=add(tmp[j+k],1ll*dp[u][j]*dp[v][k]%mo);
		for(int j=0;j<=siz[u]+siz[v];j++)dp[u][j]=tmp[j],tmp[j]=0;siz[u]+=siz[v];
	}
	for(int j=siz[u];j>=0;j--)dp[u][j+1]=add(dp[u][j+1],1ll*(siz[u]-j)*dp[u][j]%mo);siz[u]++;
}
signed main(){
	read(n);for(int i=2,p;i<=n;i++)read(p),addEdge(p,i);dosaka(1,0);
	fac[0]=1;for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mo;
	for(int i=0;i<=n;i++)
		if(i&1)ans=add(ans,mo-1ll*dp[1][i]*fac[n-i]%mo);
		else ans=add(ans,1ll*dp[1][i]*fac[n-i]%mo);
	printf("%d\\n",ans);
	return 0;
}

谢谢!!!

以上是关于[ARC121E]Directed Tree的主要内容,如果未能解决你的问题,请参考以下文章

[ARC125F]Tree Degree Subset Sum

LeetCode-面试算法经典-Java实现106-Construct Binary Tree from Inorder and Postorder Traversal(构造二叉树II)(示例(代码片

[ARC121F]Logical Operations on Tree

Lucky Array CodeForces - 121E (线段树,好题)

CF620E. New Year Tree

Codeforces Round #369 (Div. 2)-D Directed Roads