【JZOJ5068】【GDSOI2017第二轮模拟】树 动态规划+prufer序列
题面
有n个点,它们从1到n进行标号,第i个点的限制为度数不能超过A[i].
现在对于每个s (1 <= s <= n),问从这n个点中选出一些点组成大小为s的有标号无根树的方案数。
100%的数据:n <= 100
100
prufer序列
每个大小为n,有标号无根树都可以表示成一个长度为(n-2)且取值在[1,n]的序列。
这个序列就叫prufer序列。
树转prufer序列
1.每次查找一个标号最小且度数为一的点,使与之相连的点的编号加入序列尾;
2.删除树中的这个点。
prufer序列转树
1.新建一个包含[1,n]的集合;
2.找出集合中在序列中未出现的最小编号,并使之与序列头连一条边;
3.删除集合中的这个编号,以及序列头;
4.重复2-3步骤n-2次,序列则为空;
5.把集合中的剩余两个编号相连,原树复原。
性质
1.长度为(n-2)的prufer序列的集合与大小为n的带标号无根树的集合一一映射。
2.带标号无根树的任意点的度数等于,与之对应的prufer序列的对应编号出现次数+1。
Back to Problem
Pre
假设我们求出了一个prufer序列的长度\(n\),并且知道其中每个编号出现的次数\(c_i\)。
由性质2,那么这种prufer序列的贡献就是,它的不同全排列数,有:
\]
正文
所以我们把原题转化为在序列上的动态规划。
设\(f_{i,j,k}\)表示前i个点,用了j个点,序列长度为k的方案数。
那么就有,
f_{i+1,j,k}\\
f_{i+1,j+1,k+l},&l \in [0,a_i-1]
\end{cases}
\]
最终答案就是\(f_{n,s,s-2}*(s-2)!\)。
时间复杂度为\(O(n^4)\),但由于冗余状态的存在,是能卡过的。
原题是要用FFT优化到\(O(n^3*log_n)\)
Code
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ll long long
#define fo(i,x,y) for(int i=x;i<=y;i++)
#define fd(i,x,y) for(int i=x;i>=y;i--)
using namespace std;
const char* fin="tree.in";
const char* fout="tree.out";
const int inf=0x7fffffff;
const int maxn=107,mo=1004535809;
int n,a[maxn],f[maxn][maxn][maxn],fact[maxn],nf[maxn];
int qpower(int a,int b){
int c=1;
while (b){
if (b&1) c=1LL*a*c%mo;
a=1LL*a*a%mo;
b>>=1;
}
return c;
}
int ni(int v){return qpower(v,mo-2);}
int main(){
freopen(fin,"r",stdin);
freopen(fout,"w",stdout);
scanf("%d",&n);
fact[0]=1;
fo(i,1,maxn-1) fact[i]=1LL*fact[i-1]*i%mo;
fo(i,0,maxn-1) nf[i]=ni(fact[i]);
fo(i,1,n) scanf("%d",&a[i]);
memset(f,0,sizeof f);
f[1][0][0]=1;
fo(i,1,n)
fo(j,0,i-1)
fo(k,0,n){
f[i+1][j][k]=(f[i][j][k]+f[i+1][j][k])%mo;
fo(l,0,a[i]-1){
if (k+l>n) break;
f[i+1][j+1][k+l]=(f[i+1][j+1][k+l]+1LL*f[i][j][k]*nf[l])%mo;
}
}
printf("%d ",n);
fo(i,2,n) cout<<1LL*f[n+1][i][i-2]*fact[i-2]%mo<<" ";
return 0;
}
【JZOJ5068】【GDSOI2017第二轮模拟】树 动态规划+prufer序列的更多相关文章
- 【JZOJ5071】【GDSOI2017第二轮模拟】奶酪 树形dp
题面 CJY很喜欢吃奶酪,于是YJC弄到了一些奶酪,现在YJC决定和CJY分享奶酪. YJC弄到了n-1块奶酪,于是他把奶酪挂在了一棵n个结点的树上,每根树枝上挂一块奶酪,每块奶酪都有重量. YJC和 ...
- 【JZOJ5060】【GDOI2017第二轮模拟day1】公路建设 线段树+最小生成树
题面 在Byteland一共有n 个城市,编号依次为1 到n,它们之间计划修建m条双向道路,其中修建第i 条道路的费用为ci. Byteasar作为Byteland 公路建设项目的总工程师,他决定选定 ...
- [jzoj5073 GDOI2017第二轮模拟] 影魔
Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵 ...
- 【JZOJ5064】【GDOI2017第二轮模拟day2】友好城市 Kosarajo算法+bitset+ST表+分块
题面 在Byteland 一共有n 座城市,编号依次为1 到n,这些城市之间通过m 条单向公路连接. 对于两座不同的城市a 和b,如果a 能通过这些单向道路直接或间接到达b,且b 也能如此到达a,那么 ...
- GDOI2017第二轮模拟day1 总结
平民比赛 这场比赛的暴力分非常友好. 但是我并没有拿到全部的暴力分. 1(暴力分\(60/100\)) 暂时我可以拿的暴力分为\(30/100\),直接mst模拟即可. 然而当时打了个辣鸡莫队,结果爆 ...
- bzoj 1005: [HNOI2008]明明的烦恼 树的prufer序列+万进制
题目传送门 思路: 这道题需要前置知识prufer编码,这篇博客对prufer编码和这道题的分析写的很好. 这里主要讲一些对大数阶乘的分解,一个办法当然是用高精度,上面这篇博客用的是java,还有一个 ...
- 树的Prufer 编码和最小生成树计数
Prufer数列 Prufer数列是无根树的一种数列.在组合数学中,Prufer数列由有一个对于顶点标过号的树转化来的数列,点数为n的树转化来的Prufer数列长度为n-2.它可以通过简单的迭代方 ...
- 【BZOJ 1211】 1211: [HNOI2004]树的计数 (prufer序列、计数)
1211: [HNOI2004]树的计数 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2468 Solved: 868 Description 一 ...
- bzoj1211: [HNOI2004]树的计数(prufer序列+组合数学)
1211: [HNOI2004]树的计数 题目:传送门 题解: 今天刚学prufer序列,先打几道简单题 首先我们知道prufer序列和一颗无根树是一一对应的,那么对于任意一个节点,假设这个节点的度数 ...
随机推荐
- Python学习day24-面向对象的三大特征之继承
figure:last-child { margin-bottom: 0.5rem; } #write ol, #write ul { position: relative; } img { max- ...
- Compile_Netgen_WITH_OpenCascade
title: Compile_Netgen_WITH_OpenCascade date: 2016-04-23 21:14:42 tags: 结合OCCT编译Netgen date: 2016-04- ...
- PKU OJ A Bug's life
http://bailian.openjudge.cn/tm2018/G/ #include <iostream> #include <vector> #include < ...
- quartz 定时任务配置文件信息
quartz 定时任务配置文件有五大要素,配置好这五大要素,quartz 就能够正常的工作. 五大要素分别是: 1.工作的 bean:具体是哪个 Java 类来作为定时任务的文件入口,并配置该 bea ...
- [Swoole系列入门教程 5] UDP协议和demo
• 客户端服务端没有任何联系 • 指定地址跟端口,不关心消息是否发送成功 • 心跳检测不能影响到客户端• udp建立长连接
- day19 作业
今日作业 1.什么是对象?什么是类? 对象:特征和技能的结合体 类:一系列对象 相同的特征和技能的结合体 2.绑定方法的有什么特点 对象调用类内部的函数 称之为绑定方法,特点: 不同的对象调用该绑定方 ...
- git异常处理(一)
请输入提交消息来解释为什么这种合并是必要的 git 在pull或者合并分支的时候有时会遇到这个界面.可以不管(直接下面3,4步),如果要输入解释的话就需要: 1.按键盘字母 i 进入insert模式 ...
- struts2-result-servletAPI-获得参数-参数封装
1 结果跳转方式 转发 重定向 转发到Action 重定向到Action 2 访问servletAPI方式 2.1 原理 2.2 获得API 通过ActionContext ★★★★ 通过Servl ...
- Codeforces 142B(二分染色、搜索)
要点 会发现本质上棋盘分成了若干个独立集,本集合内的点放不放棋子并不影响其他集合内的 集合的划分方式就是满棋盘跳马步直到全跳过了,然后每个集合就分成两队,我们选人多的那队放棋子,人少那队当禁区 con ...
- Promise的源码实现(符合Promise/A+规范)
我们手写一个Promise/A+规范,然后安装测试脚本,以求通过这个规范. //Promise/A+源代码 // new Promise时,需要传递一个executor执行器,执行器立即执行 // e ...