Problem

\(\mathrm{Codeforces~917D}\)

题意概要:一棵 \(n\) 个节点的无向树。问在 \(n\) 个点的完全图中,有多少生成树与原树恰有 \(k\) 条边相同,对于任意 \(k\in[0,n)\) 输出答案,答案取模。

\(2\leq n\leq 100\)

Solution

这题思路新奇啊,智商又能上线了

由于暴力为枚举所有生成树,发现枚举所有生成树的高效算法为矩阵树定理,而且数据范围恰好在矩阵树复杂度接受范围内

由于矩阵树计算的是所有 生成树边权积 之和,考虑给完全图中每一条边边权设为 \(1\),若是树边则设为 \(x\),最后矩阵树消出来的行列式为一个多项式,这个多项式中 \(k\) 次项的系数即 与原树重合恰好 \(k\) 条边的生成树个数

考虑将多项式代入行列式去消不方便,可以采用代入几个数字去算,最后用拉格朗日插值去算系数,由于最后的多项式为 \(n\) 项系数,所以需要用 \(n+1\) 个值去代,不妨设为 \(1...n+1\)

总体时间复杂度 \(O(n^4)\),比容斥Dp慢多了……

拉格朗日差值

刚好正在复习拉格朗日差值,附上大致流程:

求 \(F(x)=\sum a_ix^i\),使得 \(\forall i\in[1,n],F(x_i)=y_i\)

令 \(F(x)=\sum_if_i(x)\),其中\(f_i(x_j)=\begin{cases}y_j,& j=i\\0,& j\not =i\end{cases}\)

由定义可设 \(f_i(x)=c_i\prod_{j\not = i}(x-x_j)=y_i\),可以解出 \(c_i\),反过来得到 \(f_i(x)\),最后求和得到 \(F(x)\)

其中求 \(\prod_{j\not = i}(x-x_j)\) 时,可以先预处理出 \(\prod (x-x_j)\),对于每一个 \(i\) 都将上式除以 \((x-x_i)\),这样二项式乘除法都是 \(O(n^2)\) 的

整个算法复杂度 \(O(n^2)\)

Code

//Codeforces-917D
#include <bits/stdc++.h>
using namespace std;
typedef long long ll; inline void read(int&x){
char c11=getchar();x=0;while(!isdigit(c11))c11=getchar();
while(isdigit(c11))x=x*10+c11-'0',c11=getchar();
} const int N = 113, p = 1e9+7;
struct Edge{int l,r;}e[N];
int Y[N],n; inline int qpow(int A,int B){
int res = 1; while(B){
if(B&1) res = (ll)res * A%p;
A = (ll)A * A%p, B >>= 1;
}return res;
} namespace Matrix_Tree{
int a[N][N];
int Gauss(){
for(int i=1;i<n;++i){
if(!a[i][i])
for(int j=i+1;j<n;++j)
if(a[j][i]){
for(int k=i;k<n;++k)
swap(a[i][k],a[j][k]);
break;
}
for(int j=i+1;j<n;++j)
if(a[j][i]){
int ki = (ll)a[j][i] * qpow(a[i][i],p-2)%p;
for(int k=i;k<n;++k)
a[j][k] = (a[j][k] - (ll)ki * a[i][k]%p +p)%p;
}
}
int res = 1;
for(int i=1;i<n;++i)
res = (ll)res * a[i][i]%p;
return res;
}
int calc(int x){
for(int i=1;i<n;++i)
for(int j=1;j<n;++j)
a[i][j] = 0;
for(int i=1;i<n;++i)
a[i][i] = n - 1;
for(int i=1,l,r;i<n;++i){
l = e[i].l, r = e[i].r;
a[l][r] = a[r][l] = p - x;
a[l][l] = (a[l][l] + x - 1)%p;
a[r][r] = (a[r][r] + x - 1)%p;
}
for(int i=1;i<n;++i)
for(int j=1;j<n;++j)
if(i!=j and !a[i][j])
a[i][j] = p - 1;
return Gauss();
}
} namespace Lagrange{
int Ans[N],S[N],a[N],tmp[N];
inline int calc(int n,int x){
int res = 0, pw = 1;
for(int i=0;i<=n;++i){
res = (res + (ll)pw * a[i])%p;
pw = (ll)pw * x %p;
}return res;
}
void work(){
++n, S[0] = 1;
for(int i=1;i<=n;++i){
for(int j=i;j;--j)
S[j] = S[j-1];
S[0] = 0;
for(int j=0;j<i;++j)
S[j] = (S[j] - (ll)S[j+1] * i%p +p)%p;
}
for(int i=1;i<=n;++i){
for(int j=0;j<=n;++j) tmp[j] = S[j];
for(int j=n;j;--j){
a[j-1] = tmp[j];
tmp[j-1] = (tmp[j-1] + (ll)i * tmp[j])%p;
}
int v = calc(n-1,i);
v = (ll)qpow(v,p-2) * Y[i]%p;
for(int j=0;j<n;++j)
Ans[j] = (Ans[j] + (ll)v * a[j])%p;
}
for(int i=0;i<n-1;++i)
printf("%d ",Ans[i]);
putchar(10);
}
} int main(){
read(n);
for(int i=1,x,y;i<n;++i) read(e[i].l),read(e[i].r);
for(int i=1;i<=n+1;++i) Y[i] = Matrix_Tree::calc(i);
Lagrange::work();
return 0;
}

题解-Codeforces917D Stranger Trees的更多相关文章

  1. Codeforces917D. Stranger Trees

    $n \leq 100$的完全图,对每个$0 \leq K \leq n-1$问生成树中与给定的一棵树有$K$条公共边的有多少个,答案$mod \ \ 1e9+7$. 对这种“在整体中求具有某些特性的 ...

  2. 【CF917D】Stranger Trees 树形DP+Prufer序列

    [CF917D]Stranger Trees 题意:给你一棵n个点的树,对于k=1...n,问你有多少有标号的n个点的树,与给出的树有恰好k条边相同? $n\le 100$ 题解:我们先考虑容斥,求出 ...

  3. CF917D Stranger Trees

    CF917D Stranger Trees 题目描述 给定一个树,对于每个\(k=0,1\cdots n-1\),问有多少个生成树与给定树有\(k\)条边重合. 矩阵树定理+高斯消元 我们答案为\(f ...

  4. 题解 CF917D 【Stranger Trees】

    生成树计数问题用矩阵树定理来考虑. 矩阵树定理求得的为\(\sum\limits_T\prod\limits_{e\in T}v_e\),也就是所有生成树的边权积的和. 这题边是不带权的,应用矩阵树定 ...

  5. codeforces 917D Stranger Trees

    题目链接 正解:矩阵树定理+拉格朗日插值. 一下午就搞了这一道题,看鬼畜英文题解看了好久.. 首先这题出题人给了两种做法,感觉容斥+$prufer$序列+$dp$的做法细节有点多所以没看,然而这个做法 ...

  6. 【CF917D】Stranger Trees

    题目 看题解的时候才突然发现\(zky\)讲过这道题啊,我现在怕不是一个老年人了 众所周知矩阵树求得是这个 \[\sum_{T}\prod_{e\in T}w_e\] 而我们现在的这个问题有些鬼畜了, ...

  7. CF917D. Stranger Trees & TopCoder13369. TreeDistance(变元矩阵树定理+高斯消元)

    题目链接 CF917D:https://codeforces.com/problemset/problem/917/D TopCoder13369:https://community.topcoder ...

  8. Codeforces 917D - Stranger Trees(矩阵树定理/推式子+组合意义)

    Codeforces 题目传送门 & 洛谷题目传送门 刚好看到 wjz 在做这题,心想这题之前好像省选前做过,当时觉得是道挺不错的题,为啥没写题解呢?于是就过来补了,由此可见我真是个大鸽子(( ...

  9. LeetCode题解之Leaf-Similar Trees

    1.题目描述 2.问题分析 将叶子节点的值放入vector,然后比较. 3.代码 bool leafSimilar(TreeNode* root1, TreeNode* root2) { vector ...

随机推荐

  1. NW.js使用及打包

    简介 NW.js (原名 node-webkit)是一个结合了 Chromium 和 node.js 的应用运行时,通过它可以用 HTML 和 JavaScript 编写原生应用程序.它还允许开发者从 ...

  2. Ubutun 16.04添加操作命令审计

    1.启用/var/log/messages,监控系统命令 说明:由于需要把操作命令记录到/var/log/messages,但是ubuntu默认并没有开启日志写入到这个文件 tchua@ubuntu: ...

  3. python 包以及循环导入

    包的认识 包通过文件夹来管理一系列功能相近的模块 包:一系列模块的集合体重点:包中一定有一个专门用来管理包中所有模块的文件包名:存放一系列模块的文件夹名字包名(包对象)存放的是管理模块的那个文件的地址 ...

  4. 基于.NET平台的Ocelot网关框架教程汇总

    Ocelot 框架是基于.NET 开发的 API 网关,API网关是系统内部服务暴露在外部的一个访问入口,类似于代理服务器,就像一个公司的门卫承担着寻址.限制进入.安全检查.位置引导等工作,我们可以形 ...

  5. MySQLorder by用法

    首先,order by是用来写在where之后,给多个字段来排序的一个DQL查询语句. 其次,order by写法: 1.  select 字段列表/* from 表名 where 条件 order ...

  6. python调用openstack的api,create_instance的程序解析

    python调用openstack的api,create_instance的程序解析 2017年10月17日 15:27:24 CloudXli 阅读数:848   版权声明:本文为博主原创文章,未经 ...

  7. 五一培训 清北学堂 DAY1

    今天是冯哲老师的讲授~ 1.枚举 枚举也称作穷举,指的是从问题所有可能的解的集合中一一枚举各元素. 用题目中给定的检验条件判定哪些是无用的,哪些是有用的.能使命题成立的即为其解. 例一一棵苹果树上有n ...

  8. P2522 [HAOI2011]Problem b (莫比乌斯反演)

    题目 P2522 [HAOI2011]Problem b 解析: 具体推导过程同P3455 [POI2007]ZAP-Queries 不同的是,这个题求的是\(\sum_{i=a}^b\sum_{j= ...

  9. BZOJ2655calc

    题目描述 一个序列a1,...,an是合法的,当且仅当:长度为给定的n.a1,...,an都是[1,A]中的整数.a1,...,an互不相等.一个序列的值定义为它里面所有数的乘积,即a1a2...an ...

  10. python之路day11--装饰器形成的过程、作用、装饰器的固定模式

    装饰器形成的过程# 装饰器的作用# 原则:开放封闭原则#装饰器的固定模式 import time # print(time.time()) #1551251400.416998 当前时间() #让程序 ...