noi.ac#15 题解
做了一下午还多,完全独立完成。
题意很简单:给树加一条边使得最大匹配数增加1。
什么样的边 满足条件呢?很明显,当且仅当存在一个最大匹配不选 。此时加上 边后, 构成新的匹配,匹配数 。
我们把它变成 “存在一个最大匹配不选 ” 且 “存在一个最大匹配不选 ”。这事就好做了,删 后重新算最大匹配。树的最大匹配可以dp做,。这样再加上枚举就是 的。假设这样的点叫做 “可不选点”,设 为“可不选点”的数量,答案就是 。
最大匹配的做法:
设 表示 子树中的最大匹配数, 不选/选(强制)。
那个转移的意思是,既然 要选,那肯定要和其中一个儿子匹配,枚举和儿子 匹配, 必须在子树里不选,而其它的儿子可以选或不选都行。
最后答案自然是 ,设 为树的根。
很遗憾这样不对。因为我们最开始做的转化不对。这事很好理解,因为“可以不选”并非独立的,可能我不选某个点的时候,就必须要选另外的某个点了。最简单的反例是一个三个点的链 。最大匹配显然为 ,但是不选 就要选 ,不选 就要选 ,虽然 和 都是 “可不选点”,但它俩不能同时不被选。简单来说,“可不选”不满足“合并性”,“全可不选”不代表“可全不选”。
因此正确的做法是:枚举 并删除,求剩下的树的匹配数,看是否不变。。
我们分两步做。枚举 ,并删除,求匹配数看是否不变(如果这里就变了就不用再枚举 了)。若不变(此时树被切成了若干子树),枚举 并删除,此时看 所在的那个子树的匹配数是否不变即可,其它子树就不用看了因为没受影响一定不变。
那相当于求这样的一个东西:对于每个“可不选点”,把它切掉后剩下若干个子树,求每个子树里“可不选点”数量的和。
容易想到在dp时顺便记录下“可不选点”的数量,设为 。我们尝试写出 的转移式,发现了几个问题:
- 超级难转移,虽然也不是不可以转移
- 注意到我们还需要做换根dp,那就得支持减去一个子树。本来做 就只能用 set 维护后面的 max 勉强支持减, 比 还复杂,这里笔者想不下去了,我认为要对 做换根dp是相当困难的。
总的来说就是十分困难。(事实上,我一半时间就是在搞这个,发现搞不出来)
一条路走不通了,试试看换条路走。哪里可以“换条路”呢?我们知道,在二分图中,最大匹配数+最大独立集=n。从而转化为考虑最大独立集。
最大独立集相关dp:
最大独立集的dp比最大匹配的dp简单很多,这也是转化成最大独立集的原因。
表示 子树里, 不选/选,最大独立集。
每个 贡献是独立的,很容易进行减法从而支持换根dp。
加一条边匹配数增加 ,由于 不变,就相当于最大独立集数减小 。最大独立集减小 ,当且仅当 都是最大独立集必选的点。此时,原来可以(且必须)选 ,现在它俩只能二选一了,最大独立集减小 。
和“可不选”不一样,一个必须选,另一个必须选,那么两个就都是必须选的,它具有 “合并性”,“全必选”等价于“必全选”。此时答案就是必选点个数选 个的方案数。
写出来发现又不对。这回又哪里不对了?仔细看一下,最大匹配数+最大独立集=n 只在二分图中成立,加一条边万一出来个奇环,就不是二分图了。不过加出来是偶环就是对的。
观察数据发现这样算出来总是偏大的并且大的不多。多算的也很明确,就是加一条边后,最大独立集减少了一个但是匹配数不变的方案数。此时由于 不变,最大独立集+最大匹配数=n-1 ,并且生成了一个 “奇环基环树”。
从而我们有必要研究什么样的“奇环基环树”的最大独立集+最大匹配数=n-1。研究一会发现无论怎么样的结论都很难解决原问题,因为结论都是基于环上的每个子树的,而我们很难把这个子树提取出来。
实不相瞒,我另一半时间就花在这了。
我们重新回想一下,发现有这样一个东西:
我们分两步做。枚举 ,并删除,求匹配数看是否不变(如果这里就变了就不用再枚举 了)。若不变(此时树被切成了若干子树),枚举 并删除,此时看 所在的那个子树的匹配数是否不变即可,其它子树就不用看了因为没受影响一定不变。
这里删除后求匹配数都是在树上求的。此时还没加边,可以使用 “最大独立集+最大匹配数=n” 的结论。
注意删了一个点后,点数就变成 了,此时匹配数不变意味着最大独立集减小 ,那也就是这个点是必选点。
从而,边 满足条件,当且仅当: 是(最大独立集的)必选点,且 在 子树里也是必选点。
参考上面那个没做下去的思路,我们维护 表示在 情况下的必选点个数。但我们发现有一个问题:如果 , 那要维护两种情况的必选点的交集。这不是问题,我们再设一个状态 表示总的必选点数。当一边大时,就是那一边的 ,否则表示交集。
那可以写出转移:,。 是难点。
当 时,; 当 时,。
否则就是最麻烦的情况。此时 ,也就是说
对于每个 ,它可能会选择 (即 )或者 。当 时,这俩都是选 。此时必选点数贡献 。
否则就是说 。那它可能选 也可能选 。必选点数贡献 ... 吗?
此时我们发现它的 ,但我们希望它是一个交集。
再记一个状态 表示,选 和选 的必选点的交集,不管 和 的大小关系。 那此时应该是贡献一个 。
我们发现上面求的这个东西是 情况下的 ,其实就是 。加上 后,推一推发现,转移完整了。长这样:
虽然它看起来十分丧心病狂,但也比匹配的那个转移简单很多,而且它有一个十分优秀的性质:贡献关于每个 独立。
从而我们容易写出一个换根dp (建议用结构体封装加和减,会十分简单)。
记 表示全局信息,即以 为根,整棵树的 。举个例子 就是整颗树,不选 ,最大独立集。它也就是删除 后的最大独立集。它可以换根dp得到。
关于如何求答案也很显然了:枚举必选点 (即 ),求它的每个子树里有多少必选点,加起来即可。下面的子树直接用 ,但还有一个外子树,用 的全局信息减去 的信息即可得到。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效