传送门

考虑枚举一条路径 \(u,v\),求出所有边经过它的答案

只需要求出 \(u\) 的子树内选出 \(k\) 个可以重复的点,使得它们到 \(u\) 的路径不相交

不难发现,就是从 \(u\) 的儿子的子树内各自选一个以及可以选多次 \(u\) 自己

设这个方案数为 \(f_u\)

再设 \(size_u\) 表示 \(u\) 的子树大小,\(son_u\) 表示 \(u\) 的儿子集合

考虑生成函数,设

\[A(x)=\prod_{v\in son_u}(1+size_vx)
\]

那么 \(f_u=\sum_{i=0}^{k}k^{\underline i}A_i\)

运用分治 \(FFT\) 预处理 \(f\) 可以做到 \(O(nlog^2n)\)

现在的问题是当 \(u,v\) 是祖先关系的时候,设 \(u\) 为 \(v\) 的祖先

那么 \(u\) 要计算以 \(v\) 为根的时候的子树答案

一个想法就是两遍 \(dfs\) 每次到一条边 \(u\rightarrow v\) 对于这个多项式乘上一个

\[\frac{1+(n-size_u)x}{1+size_vx}
\]

而考虑到一个点的儿子不同的 \(size\) 最多之后 \(\sqrt{n}\) 个,那么只要做 \(\sqrt{n}\) 次上面的操作,复杂度 \(O(n\sqrt{n})\)

总复杂度 \(O(nlog^2n+n\sqrt{n})\)

枚举路径可以通过子树和优化成 \(O(n)\)

  1. # include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int maxn(4e5 + 5);
  5. const int mod(998244353);
  6. inline void Inc(int &x, int y) {
  7. x = x + y >= mod ? x + y - mod : x + y;
  8. }
  9. inline void Dec(int &x, int y) {
  10. x = x - y < 0 ? x - y + mod : x - y;
  11. }
  12. inline int Add(int x, int y) {
  13. return x + y >= mod ? x + y - mod : x + y;
  14. }
  15. inline int Sub(int x, int y) {
  16. return x - y < 0 ? x - y + mod : x - y;
  17. }
  18. inline int Pow(ll x, int y) {
  19. ll ret = 1;
  20. for (; y; y >>= 1, x = x * x % mod)
  21. if (y & 1) ret = ret * x % mod;
  22. return ret;
  23. }
  24. int w[2][maxn], r[maxn], l, deg;
  25. inline void Init(int len) {
  26. int i, x, y;
  27. for (l = 0, deg = 1; deg < len; deg <<= 1) ++l;
  28. for (i = 0; i < deg; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
  29. x = Pow(3, (mod - 1) / deg), y = Pow(x, mod - 2), w[0][0] = w[1][0] = 1;
  30. for (i = 1; i < deg; ++i) w[0][i] = (ll)w[0][i - 1] * x % mod, w[1][i] = (ll)w[1][i - 1] * y % mod;
  31. }
  32. inline void DFT(int *p, int opt) {
  33. int i, j, k, t, wn, x, y;
  34. for (i = 0; i < deg; ++i) if (r[i] < i) swap(p[r[i]], p[i]);
  35. for (i = 1; i < deg; i <<= 1)
  36. for (t = i << 1, j = 0; j < deg; j += t)
  37. for (k = 0; k < i; ++k) {
  38. wn = w[opt == -1][deg / t * k];
  39. x = p[j + k], y = (ll)p[j + k + i] * wn % mod;
  40. p[j + k] = Add(x, y), p[j + k + i] = Sub(x, y);
  41. }
  42. if (opt == -1) for (i = 0, wn = Pow(deg, mod - 2); i < deg; ++i) p[i] = (ll)p[i] * wn % mod;
  43. }
  44. int val[maxn], len, tmpa[20][maxn], tmpb[20][maxn], *a, *b;
  45. void Solve(int l, int r, int *ret, int d) {
  46. if (l == r) {
  47. ret[0] = 1, ret[1] = val[l];
  48. return;
  49. }
  50. int mid = (l + r) >> 1, tmp = r - l + 2, i;
  51. Solve(l, mid, tmpa[d], d + 1), Solve(mid + 1, r, tmpb[d], d + 1);
  52. a = tmpa[d], b = tmpb[d], Init(tmp), DFT(a, 1), DFT(b, 1);
  53. for (i = 0; i < deg; ++i) a[i] = (ll)a[i] * b[i] % mod;
  54. DFT(a, -1);
  55. for (i = 0; i < tmp; ++i) ret[i] = a[i];
  56. for (i = 0; i < deg; ++i) a[i] = b[i] = 0;
  57. }
  58. int n, k, first[maxn], cnt, size[maxn], ans, tmp[maxn], dv[maxn];
  59. int f[maxn], fac[maxn], rec[maxn], inv[maxn], g[maxn], h[maxn];
  60. struct Edge {
  61. int to, next;
  62. } edge[maxn];
  63. inline void AddEdge(int u, int v) {
  64. edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++;
  65. edge[cnt] = (Edge){u, first[v]}, first[v] = cnt++;
  66. }
  67. inline int Calc(int len) {
  68. int i, ret = 0, r = min(len, k);
  69. for (i = 0; i <= r; ++i) Inc(ret, (ll)tmp[i] * fac[k] % mod * inv[k - i] % mod);
  70. return ret;
  71. }
  72. inline void PolyDiv(int len, int v) {
  73. int i, inv, invv = Pow(v, mod - 2);
  74. for (i = 0; i <= len; ++i) dv[i] = tmp[i], tmp[i] = 0;
  75. for (i = len; i; --i)
  76. if (dv[i]) {
  77. tmp[i - 1] = inv = (ll)dv[i] * invv % mod;
  78. Dec(dv[i], (ll)inv * invv % mod), Dec(dv[i - 1], inv);
  79. }
  80. }
  81. inline void PolyMul(int len, int v) {
  82. int i;
  83. for (i = len; i; --i) Inc(tmp[i], (ll)tmp[i - 1] * v % mod);
  84. }
  85. inline int Cmp(int x, int y) {
  86. return size[x] < size[y];
  87. }
  88. void Dfs1(int u, int ff) {
  89. int e, v, i, j;
  90. size[u] = 1;
  91. for (e = first[u]; ~e; e = edge[e].next)
  92. if ((v = edge[e].to) ^ ff) Dfs1(v, u), Inc(g[u], g[v]), size[u] += size[v];
  93. len = 0;
  94. for (e = first[u]; ~e; e = edge[e].next)
  95. if ((v = edge[e].to) ^ ff) val[++len] = size[v];
  96. if (!len) f[u] = 1, Inc(g[u], 1);
  97. else {
  98. Solve(1, len, tmp, 0), f[u] = Calc(len), Inc(g[u], f[u]), len = 0;
  99. for (e = first[u]; ~e; e = edge[e].next)
  100. if ((v = edge[e].to) ^ ff) val[++len] = v;
  101. sort(val + 1, val + len + 1, Cmp);
  102. for (i = 0; i <= len; ++i) rec[i] = tmp[i];
  103. for (i = 1; i <= len; ++i) {
  104. if (size[val[i]] == size[val[i - 1]]) h[val[i]] = h[val[i - 1]];
  105. else {
  106. for (j = 0; j <= len; ++j) tmp[j] = rec[j];
  107. PolyDiv(len, size[val[i]]), PolyMul(len, n - size[u]);
  108. h[val[i]] = Calc(len);
  109. }
  110. }
  111. }
  112. }
  113. void Dfs2(int u, int ff) {
  114. int e, v;
  115. for (e = first[u]; ~e; e = edge[e].next)
  116. if ((v = edge[e].to) ^ ff) Inc(ans, (ll)Sub(h[v], f[u]) * g[v] % mod), Dfs2(v, u);
  117. }
  118. int main() {
  119. memset(first, -1, sizeof(first));
  120. int i, u, v, sum = 0, mx;
  121. scanf("%d%d", &n, &k);
  122. if (k == 1) return printf("%lld\n", ((ll)n * (n - 1) >> 1) % mod), 0;
  123. mx = max(n, k);
  124. for (i = 1; i < n; ++i) scanf("%d%d", &u, &v), AddEdge(u, v);
  125. inv[0] = inv[1] = 1;
  126. for (i = 2; i <= mx; ++i) inv[i] = (ll)(mod - mod / i) * inv[mod % i] % mod;
  127. for (i = 2; i <= mx; ++i) inv[i] = (ll)inv[i - 1] * inv[i] % mod;
  128. for (i = fac[0] = 1; i <= mx; ++i) fac[i] = (ll)fac[i - 1] * i % mod;
  129. Dfs1(1, 0), Dfs2(1, 0);
  130. for (i = 1; i <= n; ++i) Inc(sum, f[i]);
  131. sum = (ll)sum * sum % mod;
  132. for (i = 1; i <= n; ++i) Dec(sum, (ll)f[i] * f[i] % mod);
  133. sum = (ll)sum * inv[2] % mod;
  134. Inc(ans, sum), printf("%d\n", ans);
  135. return 0;
  136. }

Codeforces 981H:K Paths的更多相关文章

  1. 多目标跟踪笔记一:Finding the Best Set of K Paths Through a Trellis With Application to Multitarget Tracking

    Abstract 本文提出一种寻找K最优路径的方法. k最优路径的定义:1.the sum of the metrics of all k paths in the set is minimized. ...

  2. [codeforces 293]B. Distinct Paths

    [codeforces 293]B. Distinct Paths 试题描述 You have a rectangular n × m-cell board. Some cells are alrea ...

  3. CF981H K Paths

    CF981H K Paths 题解 一道不错的分治ntt题目 题目稍微转化一下,就是所有k条链的存在交,并且交的部分都被覆盖k次 所以一定是两个点,之间路径选择k次,然后端点两开花 f[x]表示x子树 ...

  4. lintcode 中等题:k Sum ii k数和 II

    题目: k数和 II 给定n个不同的正整数,整数k(1<= k <= n)以及一个目标数字. 在这n个数里面找出K个数,使得这K个数的和等于目标数字,你需要找出所有满足要求的方案. 样例 ...

  5. R与数据分析旧笔记(十五) 基于有代表性的点的技术:K中心聚类法

    基于有代表性的点的技术:K中心聚类法 基于有代表性的点的技术:K中心聚类法 算法步骤 随机选择k个点作为"中心点" 计算剩余的点到这个k中心点的距离,每个点被分配到最近的中心点组成 ...

  6. 统计学习方法三:K近邻

    一.什么是K近邻? K近邻是一种基本的分类和回归方法. 在分类时,对新的实例,根据其K个最近邻的训练实例的类别,通过多数表决权等方式预测其类别. 通俗的讲,找K个和其关系最近的邻居,哪个类别的邻居多, ...

  7. SPSS聚类分析:K均值聚类分析

    SPSS聚类分析:K均值聚类分析 一.概念:(分析-分类-K均值聚类) 1.此过程使用可以处理大量个案的算法,根据选定的特征尝试对相对均一的个案组进行标识.不过,该算法要求您指定聚类的个数.如果知道, ...

  8. CodeForces - 1093G:Multidimensional Queries (线段树求K维最远点距离)

    题意:给定N个K维的点,Q次操作,或者修改点的坐标:或者问[L,R]这些点中最远的点. 思路:因为最后一定可以表示维+/-(x1-x2)+/-(y1-y2)+/-(z1-z2)..... 所以我们可以 ...

  9. Codeforces Gym101505G:Orchard Division(扫描线+线段树第k大)

    题目链接 题意 给出一个m*m的地图,上面有n个点,现在需要用一个自定义面积的矩形笼罩住恰好n/2个点,并且这个矩形需要有一个点在至少一个角落上,问这个矩形最小的面积是多少. 思路 有点类似于扫描线. ...

随机推荐

  1. 教你利用Node.js漏洞搞事情

    PentestingNode.js Application : Nodejs Application Security 原文地址:http://www.websecgeeks.com/2017/04/ ...

  2. svn update 产生Node remains in conflict的问题

    输入:sudo svn revert --depth=infinity frontend/web/js/workplace/organization.js 最后在执行 svn  up  就ok了

  3. js有关数组的函数

    map()和filter()函数 js的数组迭代器函数map和filter,可以遍历数组时产生新的数组,和python的map函数很类似1)filter是满足条件的留下,是对原数组的过滤(筛选):2) ...

  4. APP版本升级,测试用例总结

    APP升级主要在线升级.离线升级.当有新版本时,提示更新,用户点击更新,下载最新版本,进行安装升级,这种就是在线升级:已有升级包,安装升级包进行升级,这种就是离线升级. 在线升级.离线升级常见测试用例 ...

  5. ANR触发原理(what triggers ANR?)

    Ref: http://developer.android.com/training/articles/perf-anr.html http://stackoverflow.com/questions ...

  6. python3 + zabbix api 的使用

    喜欢需要理由吗?需要吗?当然需要,zabbix的那么多功能足以让你喜欢她,现在还有zabbix API,zabbix真让我疯了,太牛逼了,太让人喜欢了.有zabbix API我们可以做很多,自己开发w ...

  7. hive与hbase的整合

    Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供完整的sql查询功能,可以将sql语句转换为MapReduce任务进行运行.其优点学习成本低,可以通过类S ...

  8. (转)Linux ldconfig 与 ldd指令

    原文:https://blog.csdn.net/iamzhangzhuping/article/details/49203981 一.ldconfig ldconfig是一个动态链接库管理命令,为了 ...

  9. 部署nexus服务

    一.安装和启动 官网下载nexus-2.12安装包,地址:https://sonatype-download.global.ssl.fastly.net/nexus/oss/nexus-2.12.0- ...

  10. Form表单如何可以传递多个值传递List数组对象到后台的解决办法

    举例说明: 后台有一个对象 User ,结构如下: 后台有一个对象 User ,结构如下: public class User{ private String username; private Li ...