当前位置: 首页 > news >正文

NAIPC 2019 Heaps of Fun

给出一个 \(n\) 个点的有根树,每个数上有一个值,范围是 \([0,b_i]\) 中的实数。

求这个树是 heap 的概率(父节点值 < 子节点值)。

\(1\leq n\leq 300, 1\leq b_i\leq 10^9\)

非常有意思的题目!

最简单的想法是 \(f(i,j)\) 表示当前节点为 \(i\) ,值为 \(j\) 的概率,但是 \(j\) 的范围在 \(10^9\) 级别,很难的啦。

那考虑如果没有数值限制呢?所有的点范围都是 \([0,x]\) 呢?

这个时候发现只需要关注相互关系就可以了,观察到实数范围内,两个数相同的概率为 \(0\),所以只要关注这 \(n\) 个点的相互关系有多少种。

什么叫做相互关系?就是从小到大给树里面的点排序,有多少种合法的排列方法。

此时考虑的状态就是 \(f(i)\) 表示当前的节点为 \(i\) ,子树内的点有多少种排列方法。

最后 heap 的概率就是 \(\frac{f(root)}{n!}\).

但是现在发现还有另外一个要求,就是所有点的数值范围可能不一样。

首先考虑一个非常朴实的点,就是子树根节点的 \(b_{root}\) 要小于等于子树内所有的 \(b_{son}\) ,可以预处理干这个。

如果 \(b_{root}=b_{son}\) 一切都好说,就是上述分析的点,但是如果 \(b_{root}<b_{son}\) 呢?

仔细观察发现,子树中的值可以在 \([0,b_{root}]\) 也可以在 \([b_{root}, b_{son}]\) 里面,此时面临两个选择。

有一个 idea 就是可以考虑多加上一维度,\(f(i,j)\) 表示当前节点为 \(i\) ,在 \([0,b_i]\) 中有 \(j\) 个子节点的排列方法。

此时有两种情况,

  1. \(b_{root} = b_{son}\)

    \(g(root,i)\) += \(f(son,j)\times f(root, j-i)\times \frac{(b_{son}-b_{root})^{j-i}}{(j-i)!}\)

  2. \(b_{root}<b_{son}\)

\(g(root,i)+=f(son,j)\times f(root,j-i)\times\binom{i}{j}\)

最后的答案是 \(\frac{\sum_{i=0}^{n} f(root,i)\times\frac{1}{i!}}{\prod b_i}\).

时间复杂度 : \(O(n^3)\)

空间复杂度 : \(O(n^3)\)

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int N=305;
const int mod=1e9+7;
int n,m=0,rt;
vector<int>son[N];
map<int,int>Map; 
int p[N],a[N],b[N],val[N],pp[N][N][N],pw[N],ipw[N],invp[N][N],C[N][N];
int Power(int x,int k){if(k==0)return 1;int val=Power(x,k>>1);val=1ll*val*val%mod;if(k&1)val=1ll*val*x%mod;return val;
}
void get_a(int x){for(auto to:son[x]){get_a(to);a[x]=min(a[x],a[to]);}
}
int dp[N][N],f[N],g[N],h[N],sz[N];
void dfs(int x){for(auto to:son[x])dfs(to);memset(g,0,sizeof(g));g[0]=1;sz[x]=0;
//	cerr<<"x="<<x<<endl;for(auto to:son[x]){memset(h,0,sizeof(h));memset(f,0,sizeof(f));if(a[to]>a[x]){for(int i=0;i<=sz[to];i++)for(int j=i;j<=sz[to];j++){h[i]+=1ll*dp[to][j]*pp[a[x]][a[to]][j-i]%mod;h[i]%=mod;}
//			cerr<<dp[to][1]<<","<<pp[a[x]][a[to]][1]<<","<<invp[a[to]][1]<<endl;}else{for(int i=0;i<=sz[to];i++){h[i]+=dp[to][i];h[i]%=mod;}}
//		cerr<<"h:";
//		for(int i=0;i<=sz[to];i++)cerr<<h[i]<<" ";cerr<<endl;for(int i=0;i<=sz[x];i++)for(int j=0;j<=sz[to];j++){
//			if(i+j==1)cerr<<i<<","<<j<<","<<g[i]<<","<<h[j]<<","<<C[i+j][j]<<" "; f[i+j]+=1ll*g[i]*h[j]%mod*C[i+j][i]%mod;f[i+j]%=mod;}
//		cerr<<endl;
//		cerr<<"f:";
//		for(int i=0;i<=sz[x]+sz[to];i++)cerr<<f[i]<<" ";cerr<<endl;sz[x]+=sz[to];swap(f,g);}
//	cerr<<endl;//	for(int i=0;i<=sz[x];i++)cerr<<g[i]<<" ";cerr<<endl;for(int i=0;i<=sz[x];i++){dp[x][i+1]+=g[i];dp[x][i+1]%=mod; }sz[x]++;
}
signed main(){cin>>n;for(int i=1;i<=n;i++){cin>>a[i]>>p[i];b[i]=a[i];son[p[i]].push_back(i);if(!p[i])rt=i;}for(int i=1;i<=n;i++)Map[a[i]]=1;Map[0]=1;for(auto&it:Map){val[m]=it.first,it.second=m++;
//		cerr<<it.first<<","<<it.second<<" ";}
//	cerr<<endl;
//	for(int i=1;i<=n;i++)cerr<<a[i]<<" ";cerr<<endl;for(int i=1;i<=n;i++)a[i]=Map[a[i]];
//	for(int i=1;i<=n;i++)cerr<<a[i]<<" ";cerr<<endl;pw[0]=1;for(int i=1;i<=n;i++)pw[i]=1ll*pw[i-1]*i%mod;for(int i=0;i<=n;i++)ipw[i]=Power(pw[i],mod-2);for(int i=0;i<=m;i++)for(int j=i+1;j<=m;j++){pp[i][j][0]=1;for(int k=1;k<=n;k++)pp[i][j][k]=1ll*pp[i][j][k-1]*(val[j]-val[i])%mod;}for(int i=1;i<=m;i++){invp[i][0]=1;for(int k=1;k<=n;k++){invp[i][k]=Power(pp[0][i][k],mod-2);	}}for(int i=0;i<=m;i++)for(int j=i+1;j<=m;j++)for(int k=0;k<=n;k++){pp[i][j][k]=1ll*pp[i][j][k]*ipw[k]%mod;}C[0][0]=1;for(int i=1;i<=n;i++){C[i][0]=1;for(int j=1;j<=i;j++){C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;}}get_a(rt);
//	for(int i=1;i<=n;i++)cerr<<a[i]<<" ";cerr<<endl;dfs(rt);
//	for(int i=1;i<=n;i++)cerr<<sz[i]<<" ";cerr<<endl;
//	for(int i=0;i<=sz[2];i++)cerr<<dp[2][i]<<" ";cerr<<endl;int ans=0;
//	for(int i=0;i<=sz[rt];i++)cerr<<dp[rt][i]<<" ";cerr<<endl;for(int i=0;i<=sz[rt];i++){cerr<<dp[rt][i]<<","<<pp[0][a[rt]][i]<<" ";ans+=1ll*dp[rt][i]*pp[0][a[rt]][i]%mod;ans%=mod;}cerr<<endl;
//	cerr<<"ans="<<ans<<endl;for(int i=1;i<=n;i++){
//		cerr<<Power(val[a[i]],mod-2)<<" ";ans=1ll*ans*Power(b[i],mod-2)%mod;ans%=mod;}
//	cerr<<endl;cout<<ans<<endl;
//	cerr<<1ll*ans*12%mod*Power(7,mod-2)%mod<<endl;return 0;
}
/*
3
1 0
1 1
1 1
*/
/*
2 
1 0
2 1
*/
/*
2 
1 0
1 1
*/
/*
3
1 0
2 1
2 1
*/
/*
13
1 0
2 1
2 1
4 2
5 2
10 3
9 3
6 4
10 8
10 1
10000000 8
99999999 7
12 12
*/
/*
2
2 0
1 0
*/
http://www.jsqmd.com/news/324529/

相关文章:

  • 无需GPU!用StructBERT中文情感分析镜像实现高效情绪判断
  • GLM-4-9B-Chat-1M GPU算力优化:vLLM chunked prefill吞吐提升3倍实测
  • Pi0多场景落地教程:养老陪护机器人、盲人辅助导航任务分解
  • FSMN VAD RTF达0.030,处理效率是实时的33倍
  • 5分钟从克隆到推理,GLM-4.6V-Flash-WEB真香体验
  • 误删识别记录怎么办?Fun-ASR数据库备份建议
  • MedGemma-X参数详解与环境配置:Python3.10+CUDA GPU算力优化实操
  • GPEN人像修复效果惊艳!模糊人脸瞬间清晰案例展示
  • Nunchaku FLUX.1 CustomV3快速部署:RTX4090单卡开箱即用文生图方案
  • 微信小程序开发:集成Chord实现移动端视频分析
  • 一文说清ISR和普通函数的区别:图文对比说明
  • 小白必看:PasteMD剪贴板美化工具从安装到使用全攻略
  • GLM-4v-9b 5分钟快速部署教程:单卡4090也能跑的高清视觉问答模型
  • 自定义输出目录,BSHM镜像灵活又实用
  • Z-Image-Turbo竖版人像生成教程,手机壁纸轻松做
  • 通义千问3-Reranker-0.6B实战:打造高效文本检索系统
  • Qwen3-VL-2B-Instruct实战教程:从零开始部署视觉代理功能
  • EagleEye效果展示:DAMO-YOLO TinyNAS在车载DMS系统中驾驶员微表情区域定位
  • ollama部署本地大模型|translategemma-4b-it性能优化:FlashAttention-2加速图文推理
  • DAMO-YOLO TinyNAS应用实践:EagleEye支撑银行网点VIP客户动线热力图生成
  • MedGemma 1.5多场景:支持医生继续教育、患者科普生成、药企医学事务支持
  • Local SDXL-Turbo实战教程:用‘4k, realistic’后缀统一提升所有生成画质
  • Hunyuan-MT-7B入门必看:vLLM推理加速+Chainlit Web界面完整指南
  • DCT-Net人像卡通化快速上手:Flask WebUI零基础调用详解
  • 2026年如何选择靠谱的农用器械批发商?这份指南请收好
  • Qwen3-Reranker-8B应用案例:电商商品搜索排序优化实战
  • lychee-rerank-mm保姆级教程:从安装到批量排序全流程
  • Local SDXL-Turbo环境部署:无需Docker基础,AutoDL镜像直接启动Diffusers服务
  • 2026年广东艺术漆品牌选购指南与口碑公司深度解析
  • Clawdbot实战手册:Qwen3-32B代理网关的AB测试框架与效果归因分析