[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=v∈Vu∑k=0∑jdpu,j−kdpv,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=0∑n(−1)idp1,i(n−i)!
乘上
(
n
−
i
)
!
(n-i)!
(n−i)!代表除了已经不合格的点以外其它点的选择方式,但由于其它点随便选也有可能导致产生更多的点不合格,所以我们要进行容斥。
时间复杂度 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