首先可以把题目转化一下:把树拆成若干条链,每条链的颜色为其所在的树的颜色,然后排放所有的链成环,求使得相邻位置颜色不同的排列方案数。

然后本题分为两个部分:将一棵树分为1~n条不相交的链的方案数;将这些链安排顺序使得不存在两条相邻的链来自同一棵树。

第一部分显然可以O(n2)树形DP,f[i][j][0/1/2]表示i及其子树j条链,i向儿子连出0/1/2条边的方案数,然后直接背包DP即可。看似O(n3)的树形背包DP其实是O(n2)的。证明复杂度:其实DP时只循环到sz[u]/sz[v]即可,然后可以把每个转移视为儿子v内子树的每个节点和节点u内v外节点组成的点对,于是全部DP完就是枚举了所有的点对,复杂度显然O(n2)。

第二部分,考虑n个点的树划分成i条链的方案是f[i],如果不考虑环只考虑链其对应的指数生成函数为Σf[i]i!(Σ(-1)i-jC(i-1,i-j)xj/j!),其中i∈[1,n],j∈[1,i]。拓展到环上,钦定一棵树作为开头,如果该颜色有i条链,则被算了i次,然后其指数生成函数为:Σf[i](i-1)!(Σ(-1)i-jC(i-1,i-j)xj-1/(j-1)!),其中i∈[1,n],j∈[1,i]。减去首尾同色后,生成函数是这样的:Σf[i](i-1)!(Σ(-1)i-jC(i-1,i-j)xj-2/(j-2)!),其中i∈[2,n],j∈[2,i]。然后暴力卷积即可。

#include<bits/stdc++.h>
using namespace std;
const int N=,mod=;
int n,m,sum,ans,fac[N],inv[N],sz[N],f[N][N][],g[N],tmp[N][],dp[][N],b[N];
vector<int>G[N];
int qpow(int a,int b)
{
int ret=;
while(b)
{
if(b&)ret=1ll*ret*a%mod;
a=1ll*a*a%mod,b>>=;
}
return ret;
}
void dfs(int u,int fa)
{
sz[u]=,f[u][][]=;
for(int i=;i<G[u].size();i++)
if(G[u][i]!=fa)
{
int v=G[u][i];
dfs(v,u);
for(int j=;j<=sz[u]+sz[v];j++)tmp[j][]=tmp[j][]=tmp[j][]=;
for(int j=;j<=sz[u];j++)
for(int k=;k<=sz[v];k++)
{
tmp[j+k][]=(tmp[j+k][]+1ll*f[u][j][]*(f[v][k][]+2ll*f[v][k][]+2ll*f[v][k][]))%mod;
tmp[j+k-][]=(tmp[j+k-][]+1ll*f[u][j][]*(f[v][k][]+f[v][k][]))%mod;
tmp[j+k][]=(tmp[j+k][]+1ll*f[u][j][]*(f[v][k][]+2ll*f[v][k][]+2ll*f[v][k][]))%mod;
tmp[j+k-][]=(tmp[j+k-][]+1ll*f[u][j][]*(f[v][k][]+f[v][k][]))%mod;
tmp[j+k][]=(tmp[j+k][]+1ll*f[u][j][]*(f[v][k][]+2ll*f[v][k][]+2ll*f[v][k][]))%mod;
}
sz[u]+=sz[v];
for(int j=;j<=sz[u];j++)f[u][j][]=tmp[j][],f[u][j][]=tmp[j][],f[u][j][]=tmp[j][];
}
}
int C(int a,int b){return a<b?:1ll*fac[a]*inv[b]%mod*inv[a-b]%mod;}
int S(int a,int b){return (!a&&!b)?:1ll*fac[a]*C(a-,a-b)%mod;}
int main()
{
fac[]=;for(int i=;i<=;i++)fac[i]=1ll*fac[i-]*i%mod;
for(int i=;i<=;i++)inv[i]=qpow(fac[i],mod-);
scanf("%d",&m);
dp[][]=;
for(int p=;p<=m;p++)
{
scanf("%d",&n);
for(int i=;i<=n;i++)G[i].clear();
for(int i=,x,y;i<n;i++)scanf("%d%d",&x,&y),G[x].push_back(y),G[y].push_back(x);
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
f[i][j][]=f[i][j][]=f[i][j][]=;
dfs(,);
memset(g,,sizeof g);
for(int i=;i<=n;i++)g[i]=(f[][i][]+2ll*f[][i][]+2ll*f[][i][])%mod;
if(p!=m)
{
memset(b,,sizeof b);
for(int j=;j<=n;j++)
if(g[j])for(int k=,t=;k<=j;k++,t=mod-t)
b[j-k]=(b[j-k]+1ll*t*S(j,j-k)%mod*g[j])%mod;
for(int i=;i<=sum;i++)
if(dp[p-][i])for(int j=;j<=n;j++)
dp[p][i+j]=(dp[p][i+j]+1ll*C(i+j,j)*b[j]%mod*dp[p-][i])%mod;
}
else{
memset(b,,sizeof b);
for(int j=;j<=n;j++)
if(g[j])for(int k=,t=;k<j;k++,t=mod-t)
b[j--k]=(b[j--k]+1ll*t*S(j-,j-k-)%mod*g[j])%mod;
for(int i=;i<=sum;i++)
if(dp[p-][i])for(int j=;j<=n;j++)
ans=(ans+1ll*C(i-+j,j)*b[j]%mod*dp[p-][i])%mod;
}
sum+=n;
}
printf("%d",ans);
}

[JSOI2019]神经网络(树形DP+容斥+生成函数)的更多相关文章

  1. P5405-[CTS2019]氪金手游【树形dp,容斥,数学期望】

    前言 话说在\(Loj\)下了个数据发现这题的名字叫\(fgo\) 正题 题目链接:https://www.luogu.com.cn/problem/P5405 题目大意 \(n\)张卡的权值为\(1 ...

  2. HDU - 5977 Garden of Eden (树形dp+容斥)

    题意:一棵树上有n(n<=50000)个结点,结点有k(k<=10)种颜色,问树上总共有多少条包含所有颜色的路径. 我最初的想法是树形状压dp,设dp[u][S]为以结点u为根的包含颜色集 ...

  3. bzoj 4455 [Zjoi2016]小星星 树形dp&容斥

    4455: [Zjoi2016]小星星 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 643  Solved: 391[Submit][Status] ...

  4. [USACO12FEB] 附近的牛 Nearby Cows - 树形dp,容斥

    给你一棵 \(n\) 个点的树,点带权,对于每个节点求出距离它不超过 \(k\) 的所有节点权值和 \(m_i\) 随便定一个根,设\(f[i][j]\)表示只考虑子树,距离为\(j\)的权值和,\( ...

  5. bzoj 3622 DP + 容斥

    LINK 题意:给出n,k,有a,b两种值,a和b间互相配对,求$a>b$的配对组数-b>a的配对组数恰好等于k的情况有多少种. 思路:粗看会想这是道容斥组合题,但关键在于如何得到每个a[ ...

  6. 【BZOJ 4665】 4665: 小w的喜糖 (DP+容斥)

    4665: 小w的喜糖 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 94  Solved: 53 Description 废话不多说,反正小w要发喜 ...

  7. [Luogu P1450] [HAOI2008]硬币购物 背包DP+容斥

    题面 传送门:https://www.luogu.org/problemnew/show/P1450 Solution 这是一道很有意思的在背包里面做容斥的题目. 首先,我们可以很轻松地想到暴力做背包 ...

  8. 5.15 省选模拟赛 容斥 生成函数 dp

    LINK:5.15 T2 个人感觉生成函数更无脑 容斥也好推的样子. 容易想到每次放数和数字的集合无关 所以得到一个dp f[i][j]表示前i个数字 逆序对为j的方案数. 容易得到转移 使用前缀和优 ...

  9. HDU 5838 (状压DP+容斥)

    Problem Mountain 题目大意 给定一张n*m的地图,由 . 和 X 组成.要求给每个点一个1~n*m的数字(每个点不同),使得编号为X的点小于其周围的点,编号为.的点至少大于一个其周围的 ...

随机推荐

  1. 使用eclipse创建maven时遇到的问题

    转自https://www.cnblogs.com/hongmoshui/p/7994759.html   1.在eclipse中用maven创建项目,右键new>>Maven Proje ...

  2. 2.在约会网站上使用k近邻算法

    在约会网站上使用k近邻算法 思路步骤: 1. 收集数据:提供文本文件.2. 准备数据:使用Python解析文本文件.3. 分析数据:使用Matplotlib画二维扩散图.4. 训练算法:此步骤不适用于 ...

  3. MarkDown简易教程+语法

    一.标题 一个#是一级,两个#是二级,最大六级 二.字体 1.加粗 要加粗的文字左右分别用两个*号包起来 2.斜体 要倾斜的文字左右分别用一个*号包起来 3.斜体加粗 要倾斜和加粗的文字左右分别用三个 ...

  4. POJ 1260:Pearls 珍珠DP

    Pearls Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7947   Accepted: 3949 Descriptio ...

  5. C++ STD Gems02

    remove.remove_if.replace.replace_if.remove_copy_if.unique #include <iostream> #include <str ...

  6. WebSocket的简单实现&jsp

    创建一个web项目 导入依赖: <?xml version="1.0" encoding="UTF-8"?> <project xmlns=& ...

  7. 201803-1 跳一跳 Java

    思路: 一个变量plus记录叠加的数,遇到2就+2 import java.util.Scanner; public class Main { public static void main(Stri ...

  8. A - Shortest path of the king (棋盘)

    The king is left alone on the chessboard. In spite of this loneliness, he doesn't lose heart, becaus ...

  9. Miller_Rabin素性测试

    1. 为什么需要素性测试? 我们其实已经知道有一些判断素数的方法,比如: 遍历测试:待测试数n与2,3,...√n做除法判断余数是否为零,如果没有任何一个数可以整除n,则说明n为素数 Wilson定理 ...

  10. 洛谷 P1113 杂务(vector)

    题目传送门 解题思路: 本题说有些杂务是有前提条件的,而有一个特性就是某个杂务的前提一定在这个杂务前面输入,那么,这个题就瞬间沦为了黄题.对于那些有前提条件的杂务,我们只需要找它的前提条件中最晚完成的 ...