[ZJOI2016] 小星星

前言

大风天踢了会球, 立竿见影就觉得感冒了, 无敌了, 一会去医务室整点抗病毒

颓了一会好点了()

思路

首先转化题意

给你一张 nm 边的图 G 和一棵同样由这 n 个点组成的树 T, 求对树上的点有多少中标号方式 p, 使得 (u,v)T,(pu,pv)G

又是数数, 怎么做呢
你注意到 n17 , 明示了状压, 我们考虑往这个方向想

考虑树形 dp , 令 fi,S 表示 i 的子树中映射了原图中 S 中的点的方案数, 也就是说这些编号已经被使用
考虑转移, 你发现对于 fi,S , 我们需要找到 S 的一些不相交子集, 而且要确定 json(i),(pi,pj)G , 你发现仅仅靠当前的状态, 不能确定 json(i),(pi,pj)G 的条件, 所以考虑加一维

fi,j,S 表示对于 i 子树, 将 i 映射到 j , 子树中已经映射的点集为 S , 可能的方案数
考虑转移, 我们可以通过将子树一个一个插入来转移

uson(i),fi,j,SS(j,v)G,SS=fu,v,Sfi,j,S

首先要对这样转移的正确性打个补丁
很容易发现的问题是, 残留了一些非法的状态, 例如 fi,j,S 这样一个状态, 其子树有可能并没有填充完
很好想到的处理方法是, 对于所有状态, 只有 |S|=sizi 的才有意义, 对于其他的情况, 用完即弃即可

你发现这样子做的时间复杂度是 O(n33n) , 过不去
科技优化到 O(n42n) ,过不去

只能从本质上进行优化


看了下 TJ , 发现新大陆「子集反演」, 直觉告诉我其与「选择」类问题有关联

子集反演的一些基础知识 不在赘述

考虑令 f(S) 表示「至多」选择 S 中的点集进行编号, g(S) 表示「恰好」选择 S 中的点集进行编号, 套路转移

一个误区是我们必须确保 g(S) 计算的是至少用一次, 而 f 没有这个要求, 容易发现

f(S)=TSg(T)

因为是枚举集合, 所以当然也就没有组合数, 也就当然没有二项式反演的广泛性

余下的都是套路


我们思考的再深一些, 找一下与「选择」类问题的关联
发现「选择」类问题其实是抛开了「集合」的子集反演, 是更高级的版本, 因为没有集合, 所以带上了组合数

考虑这个题能不能用「选择」类问题处理, 套路的, 令 g(k) 表示「恰好」选择了 k 个编号, f(k) 表示「至多」选择了 k 个编号
容易发现

f(k)=i=0k(xi)g(i)g(k)=i=0k(1)ki(xi)f(i)

那么 f(i) 怎么计算, 很显然可以枚举集合之后同上处理

最终的答案即为

g(n)=i=0n(1)ni(ni)f(i)


但是你发现过不去, 你发现

f(k)=i=0k(xi)g(i)

并不成立, 容易发现只有对于限制等价的问题, 这样做才可以

总结

神秘的转移方式, 拆分集合的新 trick

「子集反演」解决的一类特殊问题, 常常用于优化状态压缩类的问题
注意二项式反演的适用范围, 警钟长鸣

posted @   Yorg  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示