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)\)

代码:

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. #define N 35
  4. using namespace std;
  5. 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;}
  6. const ll mod=998244353;
  7. ll ksm(ll t,ll x) {
  8. ll ans=1;
  9. for(;x;x>>=1,t=t*t%mod)
  10. if(x&1) ans=ans*t%mod;
  11. return ans;
  12. }
  13. int n,m,k;
  14. ll w[N][N];
  15. ll a[N][N];
  16. ll val[N][N];
  17. ll g[N][N][N];
  18. ll f[N*N];
  19. ll fac[N*N],ifac[N*N];
  20. ll Gauss(ll a[N][N],int n) {
  21. ll ans=1;
  22. for(int i=2;i<=n;i++) {
  23. for(int j=i;j<=n;j++) {
  24. if(a[j][i]) {
  25. if(i!=j) {
  26. ans=ans*(mod-1)%mod;
  27. swap(a[i],a[j]);
  28. }
  29. break;
  30. }
  31. }
  32. ans=ans*a[i][i]%mod;
  33. ll inv=ksm(a[i][i],mod-2);
  34. for(int j=i+1;j<=n;j++) {
  35. ll tem=inv*a[j][i]%mod;
  36. for(int k=i;k<=n;k++) a[j][k]=(a[j][k]-tem*a[i][k]%mod+mod)%mod;
  37. }
  38. }
  39. return ans;
  40. }
  41. ll dp[N*N];
  42. void Insert(int v) {
  43. for(int i=m;i>=0;i--) {
  44. dp[i]=dp[i]*(mod-v)%mod;
  45. if(i) (dp[i]+=dp[i-1])%=mod;
  46. }
  47. }
  48. void Del(int v) {
  49. for(int i=0;i<=m;i++) {
  50. if(i) (dp[i]=dp[i]-dp[i-1]+mod);
  51. dp[i]=dp[i]*ksm(mod-v,mod-2)%mod;
  52. }
  53. }
  54. int main() {
  55. n=Get(),k=Get();
  56. m=n*k+3;
  57. fac[0]=1;
  58. for(int i=1;i<=m;i++) fac[i]=fac[i-1]*i%mod;
  59. ifac[m]=ksm(fac[m],mod-2);
  60. for(int i=m-1;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
  61. for(int i=1;i<=n;i++)
  62. for(int j=1;j<=n;j++)
  63. w[i][j]=Get();
  64. for(int i=1;i<=n;i++) {
  65. for(int j=i+1;j<=n;j++) {
  66. for(int q=0;q<=k;q++) {
  67. g[i][j][q]=ksm(w[i][j],q)*ifac[q]%mod;
  68. }
  69. }
  70. }
  71. for(int x0=1;x0<=m;x0++) {
  72. for(int i=1;i<=n;i++) {
  73. for(int j=i+1;j<=n;j++) {
  74. val[i][j]=0;
  75. ll now=1;
  76. for(int q=0;q<=k;q++) {
  77. (val[i][j]+=g[i][j][q]*now)%=mod;
  78. now=now*x0%mod;
  79. }
  80. }
  81. }
  82. memset(a,0,sizeof(a));
  83. for(int i=1;i<=n;i++) {
  84. for(int j=i+1;j<=n;j++) {
  85. a[i][i]+=val[i][j];
  86. a[j][j]+=val[i][j];
  87. a[i][j]-=val[i][j];
  88. a[j][i]-=val[i][j];
  89. }
  90. }
  91. for(int i=1;i<=n;i++)
  92. for(int j=1;j<=n;j++)
  93. a[i][j]=(a[i][j]%mod+mod)%mod;
  94. f[x0]=Gauss(a,n);
  95. }
  96. dp[0]=1;
  97. for(int i=1;i<=m;i++) Insert(i);
  98. ll ans=0;
  99. for(int i=1;i<=m;i++) {
  100. Del(i);
  101. ll now=1;
  102. for(int j=1;j<=m;j++)
  103. if(i!=j) now=now*(i-j)%mod;
  104. now=ksm(now%mod+mod,mod-2);
  105. (ans+=now*dp[k]%mod*f[i])%=mod;
  106. Insert(i);
  107. }
  108. cout<<ans*fac[k]%mod<<"\n";
  109. return 0;
  110. }

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. 华为oj之字符串反转

    题目: 字符串反转 热度指数:4940 时间限制:1秒 空间限制:32768K 本题知识点: 字符串 题目描述 写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串.例如: 输入描述: 输入N ...

  2. 从锅炉工到AI专家(7)

    说说计划 不知不觉写到了第七篇,理一下思路: 学会基本的概念,了解什么是什么不是,当前的位置在哪,要去哪.这是第一篇希望做到的.同时第一篇和第二篇的开始部分,非常谨慎的考虑了非IT专业的读者.希望借此 ...

  3. CPU的load和使用率傻傻分不清

    1. 什么是Cpu的Load 使用uptime.top或者查看/proc/loadavg都可以看到CPU的load统计,这里有三个值,分别代表1分钟.5分钟和15分钟的CPU Load情况.大部分人认 ...

  4. JdbcTemplate的一次爬坑记录

    时隔三个多月,我终于想起我还有个博客,其实也不是忘了我这个博客,只是平时工作繁忙没时间去写博客,故今晚腾出时间来记录一下上次工作中遇到的一个问题,给园友们分享出来,以免入坑. 上个星期在工作中使用Jd ...

  5. 基于 Zookeeper 的分布式锁实现

    1. 背景 最近在学习 Zookeeper,在刚开始接触 Zookeeper 的时候,完全不知道 Zookeeper 有什么用.且很多资料都是将 Zookeeper 描述成一个“类 Unix/Linu ...

  6. Oracle 查询结果集行数分析

    本人曾去某金融软件公司面试,交流中面试官问的一个问题是:"如果有 A.B 两张表,A 表中有 2 条数据,B 表中有 200 条数据,请问 SELECT * FROM A,B 能查出多少条数 ...

  7. Docker最全教程——从理论到实战(三)

    往期链接: https://www.cnblogs.com/codelove/p/10030439.html https://www.cnblogs.com/codelove/p/10036608.h ...

  8. Thread之八:interrupt中断

    Java中断机制是一种协作机制,也就是说通过中断并不能直接终止另一个线程,它只是要求被中断线程在合适的时机中断自己,这需要被中断的线程自己处理中断.这好比是家里的父母叮嘱在外的子女要注意身体,但子女是 ...

  9. 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil

    封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil,代码比较简单,主要是把MongoTarget的配置.FileTarget的配置集成到类中,同时利用缓存依赖来判断是否需要重新创 ...

  10. Zabbix监控原理及架构

    什么是Zabbix? Zabbix是一个用于网络,操作系统和应用程序的开源监控软件,它旨在监视和跟踪各种网络服务,服务器和其他网络硬件的状态. 为什么需要对各类系统进行监控? 在系统构建时的正常流程中 ...