HDU 6691 Minimum Spanning Trees
题目
题意:
对于一个n个点的图,每对点 u , v u,v u,v间有 p 0 p_0 p0的几率没有边, p 1 p_1 p1的几率有权值为1的边, p 2 p_2 p2…边权 < = 4 <=4 <=4,对于 n − 1 < = t < = ( n − 1 ) ( m a x v a l o f e d g e ) n-1<=t<=(n-1)(maxval \ of \ edge) n−1<=t<=(n−1)(maxval of edge)的每个 t t t求有最小生成树且最小生成树大小为 t t t的几率 ( m o d 1000000007 ) \pmod {1000000007} (mod1000000007)
考虑克鲁斯卡尔求生成树的过程,那么我们可以从小到大加入边,在 d p dp dp上即为 f i , j f_{i,j} fi,j表示 < = i <=i <=i的边联通特定的 j j j个点的概率。
发现不好转移,但是还是可以转移的。
枚举特定的点中标号最小的点所在的由 < = i − 1 <=i-1 <=i−1的边联通的极大联通块大小,这个联通块往外连的边中考虑边权为 i i i的边,它连向了一个由 < = i <=i <=i的边联通的且不包含当前联通块的极大联通块,这个联通块是比标号最小的点所在的由 < = i <=i <=i的边联通的极大联通块小的,是一个子问题,那么它的方案数是可以在之前就计算出来的,相当于一个点有很多个儿子,我们从小到大枚举儿子子树大小然后枚举这个大小的有多少个再组合数分配标号去重,这样就可以转移了。
但是我们这样只算了联通的概率,并没有计算最小生成树的值。。。。。。
那么就再来一维?
我们用生成函数表示最后一维, x t x^t xt前的系数表示权值为 t t t的最小生成树的方案。
因为我们可以发现我们之前这个究极复杂的DP是可以算最小生成树的值的。
然后用 x = 0... ( n − 1 ) ( m a x v a l o f e d g e − 1 ) x=0...(n-1)(maxval \ of \ edge - 1) x=0...(n−1)(maxval of edge−1)带入计算答案然后插值得到多项式即可。
原题解(有几处(官方)错误):
记 f i , j f_{i,j} fi,j 表示 i 个点的图由权值$ ≤ t $的边连通的概率,初值 f 0 , 1 = 1 ; f 0 , j = 0 ( 2 ≤ j ≤ n ) f_{0,1} = 1; f_{0,j} = 0 (2 ≤ j ≤ n) f0,1=1;f0,j=0(2≤j≤n)。
假设 f i , j ( 0 ≤ i ≤ t − 1 ; 1 ≤ j ≤ n ) f_{i,j} (0 ≤ i ≤ t − 1; 1 ≤ j ≤ n) fi,j(0≤i≤t−1;1≤j≤n)均已求出,当前考虑到权值为 t 的边。考虑一个 dfs 由 ≤ t 的边
构成的连通块的过程:从 1 号点所在的由 ≤ t − 1 ≤ t − 1 ≤t−1的边构成的连通块出发,按照从小到大的顺序递归访
问其他由 ≤ t 的边构成的连通块(大小相同则优先访问块内最小编号较小的)。现在 dp 这个 dfs 过程,
记 g t , i , j g_{t,i,j} gt,i,j表示从 1 号点所在的由 ≤ t − 1 ≤ t − 1 ≤t−1 的边构成的大小为 i 的连通块出发,已经访问过的其他由 ≤ t 的
边构成的连通块大小之和是 j 的概率,按照由 ≤ t ≤ t ≤t 的边构成的连通块的大小 s 从小到大考虑,先计算出
f t , s f_{t,s} ft,s,再枚举 g t , i , j g_{t,i,j} gt,i,j 挂上多少个大小为 s 的连通块,需要和挂上的连通块之间连 ≥ t ≥ t ≥t 的边或者不连边,但
是至少有一条权值为 t 的边,并且挂上的连通块之间两两不能连权值 ≤ t ≤ t ≤t 的边。不难分析这样 dp 一次
的复杂度是 O ( k n 3 l o g n ) O(kn^3 log n) O(kn3logn)。
至此还没有考虑最小生成树,为了避免在状态里额外记录权值和,每挂上一个大小为 s 的连通块就
给概率额外乘上 x s − 1 x_{s−1} xs−1,最后会得到一个关于 x 的多项式,其中 x t x^t xt 项的系数就是最小生成树是 t + ( n − 1 ) t+ (n−1) t+(n−1)
的概率,分别取 x = 0 ; 1 ; 2 ; 3 , ( k − 1 ) ( n − 1 ) x = 0; 1; 2; 3,(k − 1)(n − 1) x=0;1;2;3,(k−1)(n−1) 代入求值,最后使用插值或者高斯消元求出多项式即可。
另外标程对于 x i = i , 0 < = i < = n x_i=i,0<=i<=n xi=i,0<=i<=n的拉格朗日插值求多项式的方法十分巧妙(我精简后的代码只有7行)。
对于把 0 0 0也带入的连续整数的拉格朗日插值。
对于 y j y_j yj后面乘上的式子的分母不是 1 1 1开始的那种 ( − 1 ) n − j ( j − 1 ) ! ( n − j ) ! (-1)^{n-j}(j-1)!(n-j)! (−1)n−j(j−1)!(n−j)!,而是 ( − 1 ) n − j j ! ( n − j ) ! (-1)^{n-j}j!(n-j)! (−1)n−jj!(n−j)!
这样我们就可以用巧妙的累和而不是直接计算求出系数。
for(int j=n;j>=i;j--) a[j]=1ll*(a[j]-a[j-1])*inv[i] \texttt{ for(int j=n;j>=i;j--) a[j]=1ll*(a[j]-a[j-1])*inv[i]} for(int j=n;j>=i;j--) a[j]=1ll*(a[j]-a[j-1])*inv[i]
这一行中,每一个 a j a_j aj会对 a i a_i ai贡献 ( i j ) ÷ i ! ∗ a [ j ] \binom{i}{j} \div {i!} * a[j] (ji)÷i!∗a[j],恰好就是 a [ j ] j ! ( i − j ) ! \frac {a[j]}{j!(i-j) !} j!(i−j)!a[j]
s[j] = ((j?s[j-1]:0) - (i-1ll) * s[j]) \texttt{s[j] = ((j?s[j-1]:0) - (i-1ll) * s[j])} s[j] = ((j?s[j-1]:0) - (i-1ll) * s[j])
这一行中, s [ j ] s[j] s[j]存的是前 i − 2 i-2 i−2个数(包括 0 , 1 , 2... i − 1 0,1,2...i-1 0,1,2...i−1)选择 j j j个他们的乘积和。
然后再加乘起来就刚好是答案,太巧也太强了。
#include<bits/stdc++.h>
#define maxn 41
#define mod 1000000007
using namespace std;int n,k;
int f[5][maxn],sp[6],p[5],g[maxn][maxn],tr[maxn][maxn],tb[maxn][maxn];
int Pow(int base,int k){int ret = 1;for(;k;k>>=1,base=1ll*base*base%mod)if(k&1)ret=1ll*ret*base%mod;return ret;
}int inv[maxn*maxn]={1,1},fac[maxn*maxn]={1,1},invf[maxn*maxn]={1,1},c[maxn*maxn][maxn*maxn],pw[maxn*maxn];vector<int>interpolation(vector<int>a,int n){// only when x_i = i , 0 <= i <= nvector<int>s(n+1),r(n+1);r[0]=a[0],s[0]=1;for(int i=1;i<=n;i++){for(int j=n;j>=i;j--) a[j]=1ll*(a[j]-a[j-1])*inv[i]%mod;for(int j=i;j>=0;j--)s[j] = ((j?s[j-1]:0) - (i-1ll) * s[j]) % mod,r[j] = (r[j] + s[j] * 1ll * a[i]) % mod;}return r;
}int main(){int T;c[0][0] = 1;for(int i=1;i<maxn*maxn;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;}for(int i=2;i<maxn*maxn;i++)fac[i] = 1ll * fac[i-1] * i % mod,inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod,invf[i] = 1ll * invf[i-1] * inv[i] %mod;for(scanf("%d",&T);T--;){scanf("%d%d",&n,&k);for(int i=0;i<=k;i++) scanf("%d",&p[i]) , p[i] = p[i] * 1ll * Pow(100,mod-2) % mod;sp[k+1] = p[0];for(int i=k;i>=0;i--) sp[i] = (sp[i+1] + p[i]) % mod;vector<int>ar;for(int x=0;x<=(k-1)*(n-1);x++){ memset(f,0,sizeof f);f[0][1] = 1;pw[0] = 1;for(int i=1;i<=n;i++) pw[i] = pw[i-1] * 1ll * x % mod;for(int t=1;t<=k;t++){memset(g,0,sizeof g);for(int i=0;i<=n;i++)for(int j=0;j+i<=n;j++){tb[i][j] = Pow(sp[t+1],i*j);tr[i][j] = (Pow(sp[t],i*j)-tb[i][j]) % mod;}for(int i=1;i<=n;i++)g[i][0] = 1;for(int s=1;s<=n;s++){for(int i=1;i<=s;i++) f[t][s] = (f[t][s] + 1ll * g[i][s-i] * c[s-1][i-1] % mod * f[t-1][i]) % mod;for(int i=1;i<=n;i++)for(int j=n-i;j>=0;j--)for(int k=1,sum=1,cr=1ll*tr[i][s]*f[t][s]%mod*pw[t-1]%mod;k*s+j<=n-i;k++){sum = 1ll * sum * cr % mod * tb[(k-1)*s+j][s] % mod * c[k*s+j][s] % mod;g[i][k*s+j] = (g[i][k*s+j] + 1ll * sum * g[i][j] % mod * invf[k]) % mod;}}}ar.push_back(f[k][n]);}ar = interpolation(ar,(k-1)*(n-1));for(int i=0;i<=(k-1)*(n-1);i++)printf("%d%c",(ar[i]+mod)%mod," \n"[i==(k-1)*(n-1)]);}
}
HDU 6691 Minimum Spanning Trees相关推荐
- HDU 4408 Minimum Spanning Tree 最小生成树计数
http://acm.hdu.edu.cn/showproblem.php?pid=4408 题意:求最小生成树个数 题解:对于Kruskal算法,我们发现,最小生成树要想用多种方法就要有长度相同的边 ...
- Lecture 16 Minimum Spanning Trees
- hdu 4408 Minimum Spanning Tree
题目连接:点击打开链接 解法:利用kruskal算法 把图划分成森林, 同一点有相同最小的权值到别的点, 通过determinant计算树的课数. 总结:模板 + 自己不太懂 = 记录 + 重新学 代 ...
- HDU 4408 - Minimum Spanning Tree(最小生成树计数)
有边权的最小生成树计数 模板 #pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostre ...
- Directed Minimum Spanning Tree: Chu-Liu/Edmonds Algorithm
我们的现代数据库大作业要求实现一个图查询系统,包括基于属性的子图查询.可达性查询(可选).最短路径查询(可选).TopK最短路径查询(可选).图形化展示(可选)等功能.分成子图同构查询小组以及可达性及 ...
- Minimum spanning tree HDU - 6954
Minimum spanning tree HDU - 6954 题意: 给定n-1个点,编号从2到n,两点a和b之间的边权重为lcm(a,b).请找出它们形成的最小生成树. 2<=n<= ...
- leetcode310. Minimum Height Trees
题目 For an undirected graph with tree characteristics, we can choose any node as the root. The result ...
- HDU 1385 Minimum Transport Cost
HDU 1385 Minimum Transport Cost 我的WA代码 AC的代码 我的WA代码 我的大概思路就是,如果i->j,如果找到一个中间点k就直接简单的将path[i][j]=k ...
- 《Boost》Part1 Minimum Spanning Tree
<Boost>Part1 Minimum Spanning Tree 1.Boost中的最小生成树介绍 MST最小生成树,是图论中的基本算法,还有一种是最大生成树,此处暂不介绍. 最小生成 ...
最新文章
- 火狐浏览器允许ajax,解决火狐浏览器发送jquery的ajax请求无效的问题
- 关于Page翻页效果--Page View Controller
- WR:中国46个饮用水供水系统评估水源水对龙头水细菌群落的“烙印”
- 让Linux系统开机速度更快的方法
- c#如何实现在两个窗体(Form)间传输数据或变量
- java中包命名常见规则
- Python基础技术点和常见错误
- 我通过了 Google 技术面试,所以你也能行!
- 手机窃取PC信息,APT基础。
- Cmake构建_指定gcc/g++版本
- ElementUI:input表单验证
- 小米手机开启Root权限
- 重磅丨教育部《高校人工智能创新行动计划》权威解读, AI人才缺口竟有500万!
- mysql常用存储引擎以及悲观锁与乐观锁
- HinM_COMPILER_cale计划和实现
- tornado源码分析(四)之future、gen.coroutine
- 编译OpenCV时错误,缺少boostdesc_bgm.i文件的问题(附带资源)
- crm订单管理系统有哪些?
- 虚拟直播与光学动作捕捉技术
- 干货 | 每天上百万通话,携程电话系统性能测试实践