传送门

抄题解

\(Task0\),随便做一下,设 \(cnt\) 为相同的边的个数,输出 \(y^{n-cnt}\)

\(Task1\),给定其中一棵树

设初始答案为 \(y^n\),首先可以发现,每有一条边和给定的树相同就会使得答案除去 \(y\)

那么可以利用矩阵树定理,已经有的边权值为 \(y^{-1}\),其它的连成完全图,权值为 \(1\)

求解行列式之后乘上 \(y^n\) 即可,\(O(n^3)\)

第一种正解 \(orz~laofu\) 即可 不会

第二种正解

一个小trick

对于求恰好 \(k\) 个的方案数,并且贡献为 \(x^k\) 的形式

可以利用二项式定理展开

\(x^k=\sum_{i=0}^{k}\binom{k}{i}(x-1)^k\)

含义为枚举所有的集合 \(E\),如果 \(E\) 是答案的子集,那么贡献为 \((x-1)^{|E|}\),否则为 \(0\)

所有子集 \(E\) 的贡献之和恰好是 \(x^k\),这样可以省去容斥

那么可以直接算 \(y^{-1}-1\) 在每一种两棵树都包含的边集 \(|E|\) 的贡献

下面的 \(y\) 默认为 \(y^{-1}-1\)

对于一种边集 \(|E|\),假设它把图分成了 \(m\) 个连通块,每个连通块大小为 \(a_i\)

运用 \(prufer\) 的知识,不难得到其生成树的方案数为 \(n^{m-2}\prod_{i=1}^{m}a_i\)

直观上来看这个东西,只能得到一个 \(O(n^2)\) 的 \(dp\),\(f_{i,j}\) 表示 \(i\) 所在连通块,大小为 \(j\)

然后考虑 \(\prod_{i=1}^{m}a_i\) 的组合意义,即从每一个连通块选出一个点的方案数

那么就可以把上面的 \(dp\) 改成 \(f_{i,0/1}\) 表示 \(i\) 所在连通块是否选择了一个点

\(O(n)\) 树形 \(dp\) 即可

\(Task2\),同样的利用那一个trick

设 \(f_i\) 表示钦定 \(i\) 条边相同的方案数

那么 \(ans=\sum_{i=0}^{n-1}f_iy^i\)

考虑计算 \(f_i\),还是直接利用 \(prufer\),容易得到

\[f_x=\sum_{\sum_{i=1}^{n-x}a_i=n}\frac{n!\prod_{i=1}^{n-x}\frac{a_i^{a_i-2}}{a_i!}}{(n-x)!}\times (n^{n-x-2}\prod_{i=1}^{n-x}a_i)^2
\]

(含义参考:分配标号,连通块之间无序)

\[f_x=\sum_{\sum_{i=1}^{n-x}a_i=n}\frac{n!n^{2(n-x-2)}\prod_{i=1}^{n-x}\frac{a_i^{a_i}}{a_i!}}{m!}
\]

根据这个式子不难得到一个 \(O(n^3)\) 的 \(dp\),枚举划分

继续推导,直接代到答案里面,可以得到

\[ans=\sum_{i=1}^{n}\frac{y^{n-i}n^{2(i-2)}}{i!}\sum_{\sum_{j=1}^{i}a_j=n}\prod_{j=1}^{i}\frac{a_j^{a_j}}{a_j!}
\]

\[=\frac{y^n}{n^4}\sum_{i=1}^{n}\frac{n^{2i}}{y^ii!}\sum_{\sum_{j=1}^{i}a_j=n}\prod_{j=1}^{i}\frac{a_j^{a_j}}{a_j!}
\]

而 \(\sum_{\sum_{j=1}^{i}a_j=n}\prod_{j=1}^{i}\frac{a_j^{a_j}}{a_j!}\) 可以写成生成函数的形式

即 \([x^n](\sum_{j=1}^{n}\frac{j^j}{j!}x^j)^i\)

代入

\[ans=\frac{y^n}{n^4}\sum_{i=1}^{n}\frac{n^{2i}}{y^ii!}[x^n](\sum_{j=1}^{n}\frac{j^j}{j!}x^j)^i
\]

\[=\frac{y^n}{n^4}[x^n]\sum_{i=1}^{n}\frac{(\frac{n^2}{y}\sum_{j=1}^{n}\frac{j^j}{j!}x^j)^i}{i!}
\]

设 \(F=\frac{n^2}{y}\sum_{j=1}^{n}\frac{j^j}{j!}x^j\)

忽略与 \(i\) 无关项,就是

\[[x^n]\sum_{i=1}^{n}\frac{F^i}{i!}
\]

这个东西直接写成无穷项的形式不会影响答案,不难发现就是

\[[x^n]e^{F}
\]

多项式 \(exp\) 即可

\(O(nlogn)\)

# include <bits/stdc++.h>
using namespace std;
typedef long long ll; const int maxn(1e5 + 5);
const int mod(998244353); inline void Inc(int &x, int y) {
x = x + y >= mod ? x + y - mod : x + y;
} inline void Dec(int &x, int y) {
x = x - y < 0 ? x - y + mod : x - y;
} inline int Add(int x, int y) {
return x + y >= mod ? x + y - mod : x + y;
} inline int Sub(int x, int y) {
return x - y < 0 ? x - y + mod : x - y;
} inline int Pow(ll x, int y) {
ll ret = 1;
for (; y; y >>= 1, x = x * x % mod)
if (y & 1) ret = ret * x % mod;
return ret;
} int n, y, op; namespace Task0 {
map < pair <int, int> , int > vis; inline void Solve() {
int i, u, v, cnt = 0;
for (i = 1; i < n; ++i) {
scanf("%d%d", &u, &v);
if (u > v) swap(u, v);
vis[make_pair(u, v)] = 1;
}
for (i = 1; i < n; ++i) {
scanf("%d%d", &u, &v);
if (u > v) swap(u, v);
if (vis.count(make_pair(u, v))) ++cnt;
}
printf("%d\n", Pow(y, n - cnt));
}
} namespace Task1 {
int first[maxn], cnt, f0[maxn], f1[maxn]; struct Edge {
int to, next;
} edge[maxn << 1]; inline void AddEdge(int u, int v) {
edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++;
edge[cnt] = (Edge){u, first[v]}, first[v] = cnt++;
} void Dfs(int u, int ff) {
int e, v, tmp;
f1[u] = f0[u] = 1;
for (e = first[u]; ~e; e = edge[e].next)
if ((v = edge[e].to) ^ ff) {
Dfs(v, u), tmp = (ll)f1[u] * f1[v] % mod * n % mod;
Inc(tmp, ((ll)f1[u] * f0[v] % mod + (ll)f0[u] * f1[v] % mod) * y % mod);
f1[u] = tmp, tmp = (ll)f0[u] * f0[v] % mod * y % mod;
Inc(tmp, (ll)f1[v] * f0[u] % mod * n % mod);
f0[u] = tmp;
}
} inline void Solve() {
int i, u, v, w = Pow(y, n), ans;
y = Pow(y, mod - 2), Dec(y, 1);
memset(first, -1, sizeof(first));
for (i = 1; i < n; ++i) scanf("%d%d", &u, &v), AddEdge(u, v);
Dfs(1, 0);
ans = (ll)f1[1] * w % mod * Pow(n, mod - 2) % mod;
printf("%d\n", ans);
}
} namespace Task2 {
int f[maxn << 2], g[maxn << 2], ans, fac[maxn], inv[maxn];
int w[2][maxn << 2], r[maxn << 2], l, deg; inline void Init(int len) {
int i, x, y;
for (l = 0, deg = 1; deg < len; deg <<= 1) ++l;
for (i = 0; i < deg; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
x = Pow(3, (mod - 1) / deg), y = Pow(x, mod - 2), w[0][0] = w[1][0] = 1;
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;
} inline void DFT(int *p, int opt) {
int i, j, k, t, wn, x, y;
for (i = 0; i < deg; ++i) if (r[i] < i) swap(p[r[i]], p[i]);
for (i = 1; i < deg; i <<= 1)
for (t = i << 1, j = 0; j < deg; j += t)
for (k = 0; k < i; ++k) {
wn = w[opt == -1][deg / t * k];
x = p[j + k], y = (ll)p[j + k + i] * wn % mod;
p[j + k] = Add(x, y), p[j + k + i] = Sub(x, y);
}
if (opt == -1) for (i = 0, wn = Pow(deg, mod - 2); i < deg; ++i) p[i] = (ll)p[i] * wn % mod;
} void Inv(int *p, int *q, int len) {
if (len == 1) {
q[0] = Pow(p[0], mod - 2);
return;
}
Inv(p, q, len >> 1);
static int a[maxn << 2], b[maxn << 2];
int tmp = len << 1, i;
Init(tmp);
for (i = 0; i < tmp; ++i) a[i] = b[i] = 0;
for (i = 0; i < len; ++i) a[i] = p[i], b[i] = q[i];
DFT(a, 1), DFT(b, 1);
for (i = 0; i < tmp; ++i) a[i] = (ll)a[i] * b[i] % mod * b[i] % mod;
DFT(a, -1);
for (i = 0; i < len; ++i) q[i] = Sub(Add(q[i], q[i]), a[i]);
} inline void Calc(int *p, int *q, int len) {
int i;
for (i = len - 2; ~i; --i) q[i + 1] = (ll)p[i] * Pow(i + 1, mod - 2) % mod;
q[0] = 0;
} inline void ICalc(int *p, int *q, int len) {
int i;
for (i = len - 2; ~i; --i) q[i] = (ll)p[i + 1] * (i + 1) % mod;
q[len - 1] = 0;
} inline void Ln(int *p, int *q, int len) {
static int a[maxn << 2], b[maxn << 2];
int tmp = len << 1, i;
for (i = 0; i < tmp; ++i) a[i] = b[i] = 0;
ICalc(p, a, len), Inv(p, b, len);
DFT(a, 1), DFT(b, 1);
for (i = 0; i < tmp; ++i) a[i] = (ll)a[i] * b[i] % mod;
DFT(a, -1), Calc(a, q, len);
} void Exp(int *p, int *q, int len) {
if (len == 1) {
q[0] = 1;
return;
}
Exp(p, q, len >> 1);
static int a[maxn << 2], b[maxn << 2];
int tmp = len << 1, i;
Init(tmp);
for (i = 0; i < tmp; ++i) a[i] = b[i] = 0;
Ln(q, a, len);
for (i = 0; i < len; ++i) a[i] = Sub(p[i], a[i]), b[i] = q[i];
Inc(a[0], 1), DFT(a, 1), DFT(b, 1);
for (i = 0; i < tmp; ++i) a[i] = (ll)a[i] * b[i] % mod;
DFT(a, -1);
for (i = 0; i < len; ++i) q[i] = a[i];
} inline void Solve() {
int i, j, k, w = Pow(y, n), len;
if (n == 1) {
printf("%d\n", y);
return;
}
if (y == 1) {
printf("%d\n", Pow(n, (n - 2) << 1));
return;
}
y = Pow(y, mod - 2), Dec(y, 1), fac[0] = inv[0] = inv[1] = 1;
for (i = 1; i <= n; ++i) fac[i] = (ll)fac[i - 1] * i % mod;
for (i = 2; i <= n; ++i) inv[i] = (ll)(mod - mod / i) * inv[mod % i] % mod;
for (i = 2; i <= n; ++i) inv[i] = (ll)inv[i] * inv[i - 1] % mod;
for (i = 1; i <= n; ++i) f[i] = (ll)Pow(i, i) * inv[i] % mod * Pow(y, mod - 2) % mod * n % mod * n % mod;
for (len = 1; len <= n; len <<= 1);
Exp(f, g, len);
ans = (ll)g[n] * w % mod * fac[n] % mod * Pow(y, n) % mod * Pow(Pow(n, mod - 2), 4) % mod;
printf("%d\n", ans);
}
} int main() {
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
scanf("%d%d%d", &n, &y, &op);
if (!op) Task0 :: Solve();
else if (op == 1) Task1 :: Solve();
else Task2 :: Solve();
return 0;
}

LOJ#2983. 「WC2019」数树的更多相关文章

  1. LOJ#2983. 「WC2019」数树 排列组合,生成函数,多项式,FFT

    原文链接www.cnblogs.com/zhouzhendong/p/LOJ2983.html 前言 我怎么什么都不会?贺忙指导博客才会做. 题解 我们分三个子问题考虑. 子问题0 将红蓝共有的边连接 ...

  2. 【LOJ】#2983. 「WC2019」数树

    LOJ2983. 「WC2019」数树 task0 有\(i\)条边一样答案就是\(y^{n - i}\) task1 这里有个避免容斥的方法,如果有\(i\)条边重复我们要算的是\(y^{n - i ...

  3. Loj #2570. 「ZJOI2017」线段树

    Loj #2570. 「ZJOI2017」线段树 题目描述 线段树是九条可怜很喜欢的一个数据结构,它拥有着简单的结构.优秀的复杂度与强大的功能,因此可怜曾经花了很长时间研究线段树的一些性质. 最近可怜 ...

  4. [LibreOJ #2983]【WC2019】数树【计数】【DP】【多项式】

    Description 此题含有三个子问题 问题1: 给出n个点的两棵树,记m为只保留同时在两棵树中的边时连通块的个数,求\(y^m\) 问题2: 给出n个点的一棵树,另外一棵树任意生成,求所有方案总 ...

  5. loj#2269. 「SDOI2017」切树游戏

    还是loj的机子快啊... 普通的DP不难想到,设F[i][zt]为带上根玩出zt的方案数,G[i][zt]为子树中的方案数,后面是可以用FWT优化的 主要是复习了下动态DP #include< ...

  6. @loj - 2093@ 「ZJOI2016」线段树

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 小 Yuuka 遇到了一个题目:有一个序列 a1,a2,..., ...

  7. @loj - 3043@「ZJOI2019」线段树

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 九条可怜是一个喜欢数据结构的女孩子,在常见的数据结构中,可怜最喜 ...

  8. LOJ #2985. 「WC2019」I 君的商店

    传送门 搬题解QwQ 首先最大值一定为 \(1\),直接扫一遍两两比较 \(O(2N)\) 求出最大值 设最大值位置为 \(a\),对于任意两个没有确定的位置 \(x,y\) 询问 \([a,x+y] ...

  9. 【LOJ】#3043. 「ZJOI2019」线段树

    LOJ#3043. 「ZJOI2019」线段树 计数转期望的一道好题-- 每个点设两个变量\(p,q\)表示这个点有\(p\)的概率有标记,有\(q\)的概率到祖先的路径上有个标记 被覆盖的点$0.5 ...

随机推荐

  1. #20155232《网络对抗》Exp9 Web安全基础

    20155232<网络对抗>Exp9 Web安全基础 本实践的目标理解常用网络攻击技术的基本原理.Webgoat实践下相关实验. 实验过程 WebGoat Webgoat是OWASP组织研 ...

  2. Servlet——提交表单信息,Servlet之间的跳转

    HTML表单标签:<form></form> 属性: actoion:  提交到的地址,默认为当前页面 method:  表单提交方式 有get和post两种方式,默认为get ...

  3. 汇编 EAX,EBX,ECX,EDX,寄存器

    知识点: 寄存器EAX 寄存器AX 寄存器AH 寄存器AL 一.EAX与AX,AH,AL关系图 一格表示一字节 #include <Windows.h> int _tmain(int ar ...

  4. 【LG3768】简单的数学题

    [LG3768]简单的数学题 题面 求 \[ (\sum_{i=1}^n\sum_{j=1}^nij\text{gcd}(i,j))\text{mod}p \] 其中\(n\leq 10^{10},5 ...

  5. docker之镜像管理命令

    一.docker image 镜像管理命令 指令 描述ls 列出本机镜像build 构建镜像来自Dockerfilehistory 查看镜像历史inspect 显示一个或多个镜像详细信息pull 从镜 ...

  6. ContentProvider示例

    http://hi.baidu.com/pekdou/item/b2a070c37552af210831c678 首先,我自己是各初学者,网上一些关于ContentProvider的例子也不少,我自己 ...

  7. Daily Scrum - 11/17

    今天小组例会内容较少.拜重阳将一个简易的UI设计好push上TFS了,其他人没有太多进展.在原有项目基础上继续开发看似工作量变少,其实开始需要弄清楚原先代码的实现架构和各种借口还是比较困难的.

  8. 人民币-欧元预测(ARIMA算法)代码

    import pandas as pd import matplotlib.pyplot as plt import statsmodels as sm from statsmodels.graphi ...

  9. Beta 冲刺 四

    团队成员 051601135 岳冠宇 031602629 刘意晗 031602248 郑智文 031602330 苏芳锃 031602234 王淇 照片 项目进展 岳冠宇 昨天的困难 数据交换比较复杂 ...

  10. Spring+Junit测试用例的使用

    1.[导包]使用Spring测试套件,需要两个jar包:junit-X.X.jar和spring-test-X.X.X.RELEASE.jar,在maven项目下可添加如下依赖: <depend ...