熟练剖分(tree) 树形DP
熟练剖分(tree) 树形DP
题目描述
分析
我们设\(f[i][j]\)为以\(i\)为根节点的子树中最坏时间复杂度小于等于\(j\)的概率
设\(g[i][j]\)为当前扫到的以\(i\)为父亲节点的所有儿子最坏时间复杂度小于等于\(j\)的概率之和
因为每遍历到一个新的节点,原来的\(g\)数组中的值就要全部更新,因此我们压掉第一维
下面我们考虑转移
对于当前枚举到的某一个节点,我们用三重循环分别扫一边
第一重循环代表当前哪一个节点充当重儿子,第二重循环枚举所有儿子,第三充循环枚举最坏时间复杂度\(k\)
如果第二重循环中枚举的儿子恰好是重儿子的话,那么父亲节点的最坏时间复杂度为\(k\)的情况可以由两种情况转移过来
第一种情况就是重儿子的时间复杂度恰好为\(k\)的概率乘上其它儿子时间复杂度小于等于\(k\)的概率
第二种情况就是其它儿子的时间复杂度恰好为\(k\)的概率乘上重儿子的时间复杂度小于等于\(k\)的概率
不要忘了减去重复的情况
如果第二重循环中枚举的儿子不是重儿子的话,那么父亲节点的最坏时间复杂度为\(k\)的情况可以由两种情况转移过来
第一种情况就是重儿子的时间复杂度恰好为\(k-1\)的概率乘上其它儿子时间复杂度小于等于\(k\)的概率
第二种情况就是其它儿子的时间复杂度恰好为\(k\)的概率乘上重儿子的时间复杂度小于等于\(k-1\)的概率
也不要忘了减去重复的情况
代码
#include<cstdio>
#include<cstring>
#include<vector>
inline int read(){
int x=0,fh=1;
char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=3e3+5;
const int mod=1e9+7;
int fa[maxn],head[maxn],tot=1,n,rt;
struct asd{
int to,next;
}b[maxn<<1];
void ad(int aa,int bb){
b[tot].to=bb;
b[tot].next=head[aa];
head[aa]=tot++;
}
int ksm(int ds,int zs){
int ans=1;
while(zs){
if(zs&1) ans=1LL*ans*ds%mod;
ds=1LL*ds*ds%mod;
zs>>=1;
}
return ans;
}
int son[maxn],siz[maxn];
long long f[maxn][maxn],g[maxn],h[maxn];
void dfs(int now){
siz[now]=1;
for(int i=head[now];i!=-1;i=b[i].next){
int u=b[i].to;
if(u==fa[now]) continue;
dfs(u);
siz[now]+=siz[u];
}
int p=ksm(son[now],mod-2);
for(int i=head[now];i!=-1;i=b[i].next){
if(b[i].to==fa[now]) continue;
for(int j=0;j<=n;j++) g[j]=1;
//初始化g数组
int zez=b[i].to;
//枚举重儿子
for(int j=head[now];j!=-1;j=b[j].next){
if(b[j].to==fa[now]) continue;
int qez=b[j].to;
//枚举其它儿子
for(int k=0;k<=siz[qez]+1;k++){
//枚举最大时间复杂度
long long qt=g[k],xz=f[qez][k];
if(k) qt-=g[k-1],xz-=f[qez][k-1];
if(zez==qez){
h[k]=(qt*f[qez][k]%mod+xz*g[k]%mod-xz*qt%mod+mod)%mod;
} else {
xz=f[qez][k-1];
if(k>1) xz-=f[qez][k-2];
h[k]=(qt*f[qez][k-1]%mod+xz*g[k]%mod-xz*qt%mod+mod)%mod;
}
}
g[0]=h[0],h[0]=0;
for(int k=1;k<=siz[qez]+1;k++){
g[k]=(g[k-1]+h[k])%mod;
h[k]=0;
}
//h数组临时存储状态
}
for(int j=siz[now];j>=1;j--){
g[j]=(g[j]-g[j-1]+mod)%mod;
//将前缀和数组还原成正常数组
}
for(int j=0;j<=siz[now];j++){
f[now][j]=(f[now][j]+g[j]*p%mod)%mod;
}
}
if(son[now]==0) f[now][0]=1;
for(int i=1;i<=siz[now]+1;i++){
f[now][i]=(f[now][i]+f[now][i-1])%mod;
}
}
int main(){
memset(head,-1,sizeof(head));
n=read();
int aa;
for(int i=1;i<=n;i++){
son[i]=read();
for(int j=1;j<=son[i];j++){
aa=read(),fa[aa]=i;
ad(i,aa),ad(aa,i);
}
}
rt=1;
while(fa[rt]) rt=fa[rt];
dfs(rt);
long long ans=0;
for(int i=1;i<=n;i++){
ans=(ans+i*(f[rt][i]-f[rt][i-1]+mod)%mod)%mod;
}
printf("%lld\n",ans);
return 0;
}
熟练剖分(tree) 树形DP的更多相关文章
- 【模拟7.14】B. 熟练剖分(tree) (概率DP)
一道概率神题,考试时没读清题考完看了学长的玄学题解看了好几个小时 首先f[i][j]表示在点 i 为根的子树中,向下最长轻链长度小于等于 j 的概率. 首先递归下去并求出子树大小,然后枚举重儿子,枚举 ...
- 20210501 序列,熟练剖分(tree),建造游乐园(play)
考场 \(65+5+0\),并列 rk2 最高分 \(55+10+10\) T1:等比数列可以写作 \(q^kx\),发现 \(q\le1000\) 且有一档分为 \(a_i\le100\),想到 \ ...
- 长链剖分优化树形DP总结
长链剖分 规定若\(x\)为叶结点,则\(len[x]=1\). 否则定义\(preferredchild[x]\)(以下简称\(pc[x]\),称\(pc[x]\)为\(x\)的长儿子)为\(x\) ...
- hdu-5834 Magic boy Bi Luo with his excited tree(树形dp)
题目链接: Magic boy Bi Luo with his excited tree Time Limit: 8000/4000 MS (Java/Others) Memory Limit: ...
- CF 461B Appleman and Tree 树形DP
Appleman has a tree with n vertices. Some of the vertices (at least one) are colored black and other ...
- codeforces 161D Distance in Tree 树形dp
题目链接: http://codeforces.com/contest/161/problem/D D. Distance in Tree time limit per test 3 secondsm ...
- hdu6035 Colorful Tree 树形dp 给定一棵树,每个节点有一个颜色值。定义每条路径的值为经过的节点的不同颜色数。求所有路径的值和。
/** 题目:hdu6035 Colorful Tree 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6035 题意:给定一棵树,每个节点有一个颜色值.定 ...
- 5.10 省选模拟赛 tree 树形dp 逆元
LINK:tree 整场比赛看起来最不可做 确是最简单的题目. 感觉很难写 不过单独考虑某个点 容易想到树形dp的状态. 设f[x]表示以x为根的子树内有黑边的方案数. 白边方案只有一种所以不用记录. ...
- Codeforces Round #263 Div.1 B Appleman and Tree --树形DP【转】
题意:给了一棵树以及每个节点的颜色,1代表黑,0代表白,求将这棵树拆成k棵树,使得每棵树恰好有一个黑色节点的方法数 解法:树形DP问题.定义: dp[u][0]表示以u为根的子树对父亲的贡献为0 dp ...
随机推荐
- (恐怕是)写得最通俗易懂的一篇关于HashMap的文章——xx大佬这样说
先看再点赞,给自己一点思考的时间,微信搜索[沉默王二]关注这个有颜值却假装靠才华苟且的程序员. 本文 GitHub github.com/itwanger 已收录,里面还有一线大厂整理的面试题,以及我 ...
- 2020-06-15:Redis分布式锁怎么解锁?
福哥答案2020-06-15: 答案来自群成员:1.setnx:del2.set:lua+del3.redisson:@Overridepublic void unlock(String lockKe ...
- 针对VM从挂机-启动后,docker相关服务的无法使用问题!
使用软件 :VMware WorkStation 使用系统:linux centOS 7 windows远程调用软件:xshell 挂机-启动状态后 先使用 service network re ...
- GRE 协议 - 和 ISP 用的协议不一样怎么办
GRE 出现的背景: 随着网络(公司)规模的增大,越来越多的公司需要在跨区域之间建设自己的分公司.但随之也就出现了这样的问题,考虑这样一个场景.公司 A 在北京和上海间开设了两家公司,由于业务的需要, ...
- CentOS7(Linux)源码安装MySQL5.7.X
介绍 软件应用最重要的就是数据库了,可是还有小伙伴不会在Linux上安装MySQL数据库,今天就来讲讲如何在CentOS7环境使用源码进行安装MySQL5.7.X. MySQL官网下载链接:https ...
- 海豚星空扫码投屏 Android 接收端 SDK 集成 六步骤
一 跟目录的build.gradle添加私有mevan仓库 maven {url 'http://nexus.dolphinstar.cn/repo/openmavenx'} 二 app/build. ...
- Java之Annotation(注解)——注解处理器
如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用处了.使用注解的过程中,很重要的一部分就是创建于使用注解处理器.Java SE5扩展了反射机制的API,以帮助程序员快速的构造自定义注解处 ...
- 痞子衡嵌入式:解锁i.MXRTxxx上FlexSPI模块自带的地址重映射(Remap)功能
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT三位数系列隐藏的FlexSPI Remap功能. 前段时间痞子衡写了一篇文章 <利用i.MXRT1060,1010上新 ...
- 一文说通Jwt、Session、Cooike区别
JWT 全称是 JSON Web Token,是目前非常流行的跨域认证解决方案,在单点登录场景中经常使用到. 有些人觉得它非常好用,用了它之后就不用在服务端借助 redis 实现认证过程了,但是,还有 ...
- git 生成并添加 SSH key
git config --global user.name "wangjunqiang" git config --global user.email "wangjunq ...