[JSOI2019]神经网络(树形DP+容斥+生成函数)
首先可以把题目转化一下:把树拆成若干条链,每条链的颜色为其所在的树的颜色,然后排放所有的链成环,求使得相邻位置颜色不同的排列方案数。
然后本题分为两个部分:将一棵树分为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+容斥+生成函数)的更多相关文章
- P5405-[CTS2019]氪金手游【树形dp,容斥,数学期望】
前言 话说在\(Loj\)下了个数据发现这题的名字叫\(fgo\) 正题 题目链接:https://www.luogu.com.cn/problem/P5405 题目大意 \(n\)张卡的权值为\(1 ...
- HDU - 5977 Garden of Eden (树形dp+容斥)
题意:一棵树上有n(n<=50000)个结点,结点有k(k<=10)种颜色,问树上总共有多少条包含所有颜色的路径. 我最初的想法是树形状压dp,设dp[u][S]为以结点u为根的包含颜色集 ...
- bzoj 4455 [Zjoi2016]小星星 树形dp&容斥
4455: [Zjoi2016]小星星 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 643 Solved: 391[Submit][Status] ...
- [USACO12FEB] 附近的牛 Nearby Cows - 树形dp,容斥
给你一棵 \(n\) 个点的树,点带权,对于每个节点求出距离它不超过 \(k\) 的所有节点权值和 \(m_i\) 随便定一个根,设\(f[i][j]\)表示只考虑子树,距离为\(j\)的权值和,\( ...
- bzoj 3622 DP + 容斥
LINK 题意:给出n,k,有a,b两种值,a和b间互相配对,求$a>b$的配对组数-b>a的配对组数恰好等于k的情况有多少种. 思路:粗看会想这是道容斥组合题,但关键在于如何得到每个a[ ...
- 【BZOJ 4665】 4665: 小w的喜糖 (DP+容斥)
4665: 小w的喜糖 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 94 Solved: 53 Description 废话不多说,反正小w要发喜 ...
- [Luogu P1450] [HAOI2008]硬币购物 背包DP+容斥
题面 传送门:https://www.luogu.org/problemnew/show/P1450 Solution 这是一道很有意思的在背包里面做容斥的题目. 首先,我们可以很轻松地想到暴力做背包 ...
- 5.15 省选模拟赛 容斥 生成函数 dp
LINK:5.15 T2 个人感觉生成函数更无脑 容斥也好推的样子. 容易想到每次放数和数字的集合无关 所以得到一个dp f[i][j]表示前i个数字 逆序对为j的方案数. 容易得到转移 使用前缀和优 ...
- HDU 5838 (状压DP+容斥)
Problem Mountain 题目大意 给定一张n*m的地图,由 . 和 X 组成.要求给每个点一个1~n*m的数字(每个点不同),使得编号为X的点小于其周围的点,编号为.的点至少大于一个其周围的 ...
随机推荐
- 创建了以个vagrant box centos php7 nginx swoole git
php7.2.9 centos7 nginx.1.16 swoole4.4.4 下载地址 链接:https://pan.baidu.com/s/14p7xIa0ZZigRuYvZxnMsYA 提取 ...
- quartz详解1:初步了解quartz
http://blog.itpub.NET/11627468/viewspace-1763389/ 一.引入 你曾经需要应用执行一个任务吗?这个任务每天或每周星期二晚上11:30,或许仅仅每个月的最后 ...
- 一、VIP课程:互联网工程专题 02-Git服务搭建与版本分支管理
第二课:搭建企业私有Git服务.docx 课程概要: GIT远程通信协议详解 基于gogs 搭建WEB管理服务 一.GIT服务器搭建方式 上一节课我们讲过GIT是一个分布式版本管理系统,既然是分布那么 ...
- 解决fixed布局里内容不滚动问题
//注意给父级加上 (1)横向滚动 left:0; right:0; 然后想要横向滚动的话 overflow-x:scroll; overflow-y:hidden; (2)竖直方向滚动top:0;b ...
- gabor滤波器
https://blog.csdn.net/u013709270/article/details/49642397 https://github.com/xuewenyuan/Gabor_Visual ...
- 冒泡排序_python
def popdata(ls): for i in range(len(ls)): for j in range(i+1,len(ls)): if ls[i]>ls[j]: # tmp=ls[i ...
- Java哪些集合类是线程安全的?
早在jdk的1.1版本中,所有的集合都是线程安全的.但是在1.2以及之后的版本中就出现了一些线程不安全的集合,为什么版本升级会出现一些线程不安全的集合呢?因为线程不安全的集合普遍比线程安全的集合效率高 ...
- stegsolve使用方法
Stegsolve使用方法(是因为ctf题总是遇到并且目前百度没有十分详细的探究说明) 这个没什么好说的,打开文件 ,保存,退出 在分析里面从上到下的依次意思是 File Format:文件格式 Da ...
- Java自学-集合框架 聚合操作
聚合操作 步骤 1 : 聚合操作 JDK8之后,引入了对集合的聚合操作,可以非常容易的遍历,筛选,比较集合中的元素. 像这样: String name =heros .stream() .sorted ...
- nodejs(10)express路由
后端路由 前端请求的URL地址,都要对应一个后端的处理函数,那么 这种URL地址到 处理函数之间的对应关系,就叫做后端路由: 在Express中,路由的主要职责 就是 把客户端的请求,分发到对应的处理 ...