Luogu P5296 [北京省选集训2019]生成树计数

题目链接

题目大意:给定每条边的边权。一颗生成树的权值为边权和的\(k\)次方。求出所有生成树的权值和。

我们列出答案的式子:

设\(E\)为我们枚举的生成树的边集。

\[Ans=\sum_{E}(\sum_{i\in E}w_i)^k\\
=\sum_E \prod_{i\in E} \binom{k}{a_i}w_i^{a_i}[\sum_{i\in E}a_i=k]\\
=\sum_E \frac{1}{k!} \prod_{i\in E} \frac{1}{a_i!} w_i^{a_i}[\sum_{i\in E}a_i=k]
\]

我们知道,基尔霍夫矩阵求出来的东西是:

\[\sum_{E}\prod_{i\in E}w_i
\]

但是对于上面那个式子,我们发现每条边其实是个多项式:

\[w(x)=\sum_{i=0}^k\frac{1}{i!}w^i
\]

进一步发现,最终答案的多项式的项数是\(n*k\)(大概吧)。

于是我们带入大于\(n*k+1\)个值进去,用矩阵树定理算出对应的值,然后拉格朗日插值暴力算出第\(k\)项的系数(应该有更好的方法)。

复杂度:\(O(n^4k)\)

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 35 using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;} const ll mod=998244353;
ll ksm(ll t,ll x) {
ll ans=1;
for(;x;x>>=1,t=t*t%mod)
if(x&1) ans=ans*t%mod;
return ans;
} int n,m,k;
ll w[N][N];
ll a[N][N];
ll val[N][N];
ll g[N][N][N];
ll f[N*N];
ll fac[N*N],ifac[N*N];
ll Gauss(ll a[N][N],int n) {
ll ans=1;
for(int i=2;i<=n;i++) {
for(int j=i;j<=n;j++) {
if(a[j][i]) {
if(i!=j) {
ans=ans*(mod-1)%mod;
swap(a[i],a[j]);
}
break;
}
}
ans=ans*a[i][i]%mod;
ll inv=ksm(a[i][i],mod-2);
for(int j=i+1;j<=n;j++) {
ll tem=inv*a[j][i]%mod;
for(int k=i;k<=n;k++) a[j][k]=(a[j][k]-tem*a[i][k]%mod+mod)%mod;
}
}
return ans;
} ll dp[N*N]; void Insert(int v) {
for(int i=m;i>=0;i--) {
dp[i]=dp[i]*(mod-v)%mod;
if(i) (dp[i]+=dp[i-1])%=mod;
}
} void Del(int v) {
for(int i=0;i<=m;i++) {
if(i) (dp[i]=dp[i]-dp[i-1]+mod);
dp[i]=dp[i]*ksm(mod-v,mod-2)%mod;
}
} int main() {
n=Get(),k=Get();
m=n*k+3;
fac[0]=1;
for(int i=1;i<=m;i++) fac[i]=fac[i-1]*i%mod;
ifac[m]=ksm(fac[m],mod-2);
for(int i=m-1;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod; for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
w[i][j]=Get();
for(int i=1;i<=n;i++) {
for(int j=i+1;j<=n;j++) {
for(int q=0;q<=k;q++) {
g[i][j][q]=ksm(w[i][j],q)*ifac[q]%mod;
}
}
}
for(int x0=1;x0<=m;x0++) {
for(int i=1;i<=n;i++) {
for(int j=i+1;j<=n;j++) {
val[i][j]=0;
ll now=1;
for(int q=0;q<=k;q++) {
(val[i][j]+=g[i][j][q]*now)%=mod;
now=now*x0%mod;
}
}
}
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++) {
for(int j=i+1;j<=n;j++) {
a[i][i]+=val[i][j];
a[j][j]+=val[i][j];
a[i][j]-=val[i][j];
a[j][i]-=val[i][j];
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=(a[i][j]%mod+mod)%mod;
f[x0]=Gauss(a,n);
}
dp[0]=1;
for(int i=1;i<=m;i++) Insert(i);
ll ans=0;
for(int i=1;i<=m;i++) {
Del(i);
ll now=1;
for(int j=1;j<=m;j++)
if(i!=j) now=now*(i-j)%mod;
now=ksm(now%mod+mod,mod-2);
(ans+=now*dp[k]%mod*f[i])%=mod;
Insert(i);
}
cout<<ans*fac[k]%mod<<"\n";
return 0;
}

Luogu P5296 [北京省选集训2019]生成树计数的更多相关文章

  1. P5296 [北京省选集训2019]生成树计数

    P5296 [北京省选集训2019]生成树计数 题意 求一个带权无向图所有生成树边权和的 \(k\) 次方的和. 思路 首先有一个结论:\(a^i\) 的 EGF 卷 \(b^i\) 的 EGF 等于 ...

  2. 洛谷 P4002 - [清华集训2017]生成树计数(多项式)

    题面传送门 神题. 考虑将所有连通块缩成一个点,那么所有连好边的生成树在缩点之后一定是一个 \(n\) 个点的生成树.我们记 \(d_i\) 为第 \(i\) 个连通块缩完点之后的度数 \(-1\), ...

  3. Loj 2320.「清华集训 2017」生成树计数

    Loj 2320.「清华集训 2017」生成树计数 题目描述 在一个 \(s\) 个点的图中,存在 \(s-n\) 条边,使图中形成了 \(n\) 个连通块,第 \(i\) 个连通块中有 \(a_i\ ...

  4. 雅礼集训2019 D7T2 Subsequence

    雅礼集训2019 D7T2 Subsequence 直接贴题解: 平衡树代码: #include<bits/stdc++.h> #define ll long long #define N ...

  5. 2019暑期金华集训 Day1 组合计数

    自闭集训 Day1 组合计数 T1 \(n\le 10\):直接暴力枚举. \(n\le 32\):meet in the middle,如果左边选了\(x\),右边选了\(y\)(且\(x+y\le ...

  6. 生成树计数 Matrix-Tree 定理 学习笔记

    一直都知道要用Matrix-Tree定理来解决生成树计数问题,但是拖到今天才来学.博主数学不好也只能跟着各位大佬博客学一下它的应用以及会做题,证明实在是不会. 推荐博客: https://www.cn ...

  7. 【BZOJ1002】【FJOI2007】轮状病毒(生成树计数)

    1002: [FJOI2007]轮状病毒 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1766  Solved: 946[Submit][Status ...

  8. SPOJ 104 HIGH - Highways 生成树计数

    题目链接:https://vjudge.net/problem/SPOJ-HIGH 解法: 生成树计数 1.构造 基尔霍夫矩阵(又叫拉普拉斯矩阵) n阶矩阵 若u.v之间有边相连 C[u][v]=C[ ...

  9. 「UVA10766」Organising the Organisation(生成树计数)

    BUPT 2017 Summer Training (for 16) #6C 题意 n个点,完全图减去m条边,求生成树个数. 题解 注意可能会给重边. 然后就是生成树计数了. 代码 #include ...

随机推荐

  1. Java 的强引用、弱引用、软引用、虚引用

    1.强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.如下: Object o=new Object(); // 强引用 当内存空间 ...

  2. DocX开源WORD操作组件的学习系列一

    DocX学习系列 DocX开源WORD操作组件的学习系列一 : http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_sharp_001_docx1.htm ...

  3. 页面优化,DocumentFragment对象详解

    一.前言 最近项目不是很忙,所以去看了下之前总想整理的重汇和回流的相关资料,关于回流优化,提到了DocumentFragment的使用,这个对象在3年前我记得是有看过的,但是一直没深入了解过,所以这里 ...

  4. SpringCloud(2) 服务注册和发现Eureka Server

    一.简介 EureKa在Spring Cloud全家桶中担任着服务的注册与发现的落地实现.Netflix在设计EureKa时遵循着AP原则,它基于REST的服务,用于定位服务,以实现云端中间层服务发现 ...

  5. 服务注册中心之ZooKeeper系列(二) 实现一个简单微服务之间调用的例子

    上一篇文章简单介绍了ZooKeeper,讲了分布式中,每个微服务都会部署到多台服务器上,那服务之间的调用是怎么样的呢?如图: 1.集群A中的服务调用者如何发现集群B中的服务提供者呢? 2.集群A中的服 ...

  6. k8s架构分析(二)--技术流ken

    master节点 k8s的集群由master和node组成,节点上运行着若干k8s服务. master节点之上运行着的后台服务有kube-apiserver .kube-scheduler.kube- ...

  7. 【.NET Core项目实战-统一认证平台】第七章 网关篇-自定义客户端限流

    [.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章我介绍了如何在网关上增加自定义客户端授权功能,从设计到编码实现,一步一步详细讲解,相信大家也掌握了自定义中间件的开发技巧了,本篇我们 ...

  8. C# 【一】进程 , 线程 , 微线程 , 同步 , 异步 , 并发 , 并行 , 阻塞 , 非阻塞

    一 理解篇 前言 本文仅仅用作借鉴使用,作者刚入行不久,所以请不小心看到这篇文章的朋友,手下留情. 本文以小故事的形式进行叙述,逻辑不通之处.请理解. 如有错误 ,欢迎指出. 谢谢.          ...

  9. Nunit的尝试

    (ps:没有代码,只有理论) 单元测试 单元测试(Unit Test)的一个测试用例(Test Case)是一小段代码,用于测试一个小的程序功能的行为是否正常,保证开发的功能子项能正确完成并实现其基本 ...

  10. Java开发笔记(四十九)关键字super的用法

    前面介绍了如何从Bird类继承而来Swallow类,按道理子类应当继承父类的所有要素,但是对于构造方法来说,Swallow类仅仅继承了Bird类的默认构造方法,并未自动继承带参数的构造方法.如果子类想 ...