Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 323|回复: 0

[默认分类] LOJ #2542. 「PKUWC 2018」随机游走(最值反演 + 树上期望dp)

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2018-6-3 14:42:11 | 显示全部楼层 |阅读模式

    写在这道题前面 : 网上的一些题解都不讲那个系数是怎么推得真的不良心 TAT
    (不是每个人都有那么厉害啊 , 我好菜啊)
    而且 LOJ 过的代码千篇一律 ... 那个系数根本看不出来是什么啊 TAT
    后来做了 HDU 4035 终于会了.... 感谢 雕哥的帮助 !!!


    题意 : #2542. 「PKUWC 2018」随机游走
    题解 :

    原本的模型好像我不会那个暴力dp .... 就是直接统计点集中最后经过的点的期望 , 也就是点集中到所有点步数最大值的期望 . (也许可以列方程高斯消元 ? 似乎没分)
    但我们考虑转化一下 (因为原来 有道CLJ的题 也是求这个) 把最大值的期望用 最值反演(MinMax容斥) 转化成最小值的期望 就可以算了 ...

    最值反演 (又称 MinMax容斥 ) :
    \[\displaystyle \max\{S\}=\sum_{T\subseteq S}(-1)^{|T|-1}\min\{T\}\]
    其中 \(S\) 是全集 , \(T\) 是它的一个子集 , 就有这个神奇的定理 ...
    证明 ( 来自 DOFY大大的博客 ) :
    设最大值为 \(x \in S\) ,那么构造映射 \(f(T) \to x \in T~?~T−x:T+x\) , 也就是有 \(x\) 就去掉 , 没有就加上 。那么当 \(T\) 不为空和 \({x}\) 时,\(T\) 与 \(f(T)\) 因为只相差一个最大值,最小值肯定相同,集合大小只相差 \(1\) ,就抵消了(一一映射),因为空集没有最小值,所以最后只剩下 \(\{x\}\) 的贡献。

    然后有了这个 , 每次我们只需要求经过点集中点步数最少的贡献 .
    假设我们当前有一个集合 \(S\) , 我们用 \(f(u)\) 表示从 \(u\) 出发 , 第一次访问 \(S\) 中节点的期望步数 .
    所以我们有一些显然的式子 :

    \(u \in S:\) \[f(u)=0\]
    \(u \not \in S:\) 令 \(d\) 为 \(u\) 在树上的度数(连出来边数) , \(\mathrm{ch}\) 为 \(u\) 的儿子 , \(\mathrm{fa}\) 为 \(u\) 的父亲 . \[\displaystyle f(u)=[f(\mathrm{fa})+1+\sum (f(\mathrm{ch})+1)] \times \frac{1}{d}\] \[\displaystyle =\frac{1}{d}f(\mathrm{fa})+\frac{1}{d}\sum f(\mathrm{ch})+1\]

    不难发现 每个点的答案可以只保留它父亲的答案和一个常数的贡献
    ( 可以理解成全都能倒推回去 , 因为那个就算没有 \(u \in S\) 的限制 , 叶子的贡献也只与父亲有关 )
    假设令它为 \[f(u)=A_uf(\mathrm{fa})+B_u\] 以及 \(v = \mathrm{ch}\)
    那么有 \[\displaystyle \sum f(\mathrm{ch})=\sum f(v) = \sum(A_v f_u + B_v)\]
    把这个回代就有
    \[\displaystyle (1-\frac{\sum A_v}{d}) f(u) = \frac{1}{d}f(\mathrm{fa})+(1+\frac{B_v}{d})\]
    除过去就可以得到每个递推式的 \(A,B\) 了 qwq
    然后随便写写就行啦 , 复杂度 \(O((n+Q) \cdot 2^n)\) ... 其实后面那个复杂度是对于每个询问枚举子集 .
    预处理的话 , 复杂度就变成 \(O(n\cdot 2^n + 3^n)\) 啦 ...
    似乎都可以轻松过掉 ?

    代码 :


    1. [code]#include <bits/stdc++.h>
    2. #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
    3. #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
    4. #define Set(a, v) memset(a, v, sizeof(a))
    5. using namespace std;
    6. inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
    7. inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
    8. inline int read() {
    9.     int x = 0, fh = 1; char ch = getchar();
    10.     for (; !isdigit(ch); ch = getchar()) if (ch == "-") fh = -1;
    11.     for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
    12.     return x * fh;
    13. }
    14. void File() {
    15. #ifdef zjp_shadow
    16.     freopen ("2542.in", "r", stdin);
    17.     freopen ("2542.out", "w", stdout);
    18. #endif
    19. }
    20. typedef long long ll;
    21. const int Mod = 998244353;
    22. inline ll fpm(ll x, int power) {
    23.     ll res = 1; x = (x % Mod + Mod) % Mod;
    24.     for (; power; power >>= 1, (x *= x) %= Mod)
    25.         if (power & 1) (res *= x) %= Mod;
    26.     return res;
    27. }
    28. const int N = 20;
    29. int n, Q, rt, d[N];
    30. vector<int> G[N]; ll A[N], B[N], invd[N];
    31. void Dp(int u, int fa, int S) {
    32.     if ((1 << (u - 1)) & S) { A[u] = B[u] = 0; return ; }
    33.     ll totA = 0, totB = 0;
    34.     for (int v : G[u]) if (v ^ fa)
    35.         Dp(v, u, S), totA += A[v], totB += B[v];
    36.     totA %= Mod, totB %= Mod;
    37.     ll coef = fpm(Mod + 1 - totA * invd[u], Mod - 2);
    38.     A[u] = invd[u] * coef % Mod;
    39.     B[u] = (1 + totB * invd[u] % Mod) * coef % Mod;
    40. }
    41. ll Minv[1 << 18]; int bit[1 << 18];
    42. int main () {
    43.     File();
    44.     n = read(); Q = read(); rt = read();
    45.     For (i, 1, n - 1) {
    46.         int u = read(), v = read();
    47.         G[u].push_back(v); G[v].push_back(u);
    48.         ++ d[u]; ++ d[v];
    49.     }
    50.     For (i, 1, n) invd[i] = fpm(d[i], Mod - 2);
    51.     int maxsta = (1 << n) - 1;
    52.     For (i, 0, maxsta) {
    53.         Dp(rt, 0, i);
    54.         Minv[i] = B[rt];
    55.         bit[i] = bit[i >> 1] + (i & 1);
    56.     }
    57.     while (Q --) {
    58.         int k = read(), sta = 0;
    59.         while (k --) sta |= (1 << (read() - 1));
    60.         ll ans = 0;
    61.         for (int i = sta; i; i = (i - 1) & sta)
    62.             ans += (bit[i] & 1 ? 1 : -1) * Minv[i];
    63.         ans = (ans % Mod + Mod) % Mod;
    64.         printf ("%lld\n", ans);
    65.     }
    66.     return 0;
    67. }
    复制代码
    [/code]
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-24 11:04 , Processed in 0.373143 second(s), 37 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表