计数dp与容斥

本文参考自[彭博-问题的常用技巧]

I.条件计数

  • 问题最难的点一般有两种途径,不重不漏的计数和容斥,如果要不重不漏的计数就要寻找一个唯一能表示计算的目标的量

1.CF1264D2

递归定义合法括号序列及其深度:

• 空串是合法括号序列,深度为 0 。

• 如果 s 是合法括号序列,那么 (s) 也是合法括号序列,深度
为 s 的深度加一。

• 如果 s,t 是合法括号序列,那么 st 也是合法括号序列,深度
为 s,t 的深度的较大值。

定义任意一个括号序列的深度为其所有合法括号子序列的深度的
最大值。
给出一个包含 ()? 的字符串,? 可以任意替换为) 或 ( ,求出每
一种替换方案的深度之和。
(n ≤ 10^6)

solution

考虑假设我们已知一个括号序列(不一定合法),如何计算其深度

可以发现最优方案一定包含一个((((((((......))))))))的形式,满足左括号和右括号数相等且一一对应

容易想到枚举中间的那个位置,然后算一下即可

2.AGC052C Nondivisible Prefix Sums

给定质数 P 和长度 n 。

对于 ((P-1)^n) 个值域在 ([1, P-1]) 的数列,称它是好的,当且仅
当存在一种方法把它重排,使得每个前缀和都不是 P 的倍数。
求好的数列个数。

(1 ≤ n ≤ 5000, 3 ≤ P ≤ 10^8)

solution

AGC yyds!很妙的题

首先如果和是 P 的倍数,那么一定不行

我们考虑这么一种构造方法

每次取剩余出现次数最多的数去填,不行就换次多的,注意到这种方法会不合法当且仅当后面填 x 不合法且数列中仅剩 x

注意到根据这种方法,如果众数出现次数(leq n / 2),那么一定合法,这个可以用数学归纳法证明

我们考虑将众数消到(leq frac{n}{2}),不妨设众数为1(如果不是就所有数都乘以逆元),我们考虑一直填 1 ,如果不行就换一个数,注意不行是,前缀和必然为 (P-1) ,如果此时填 (a_i) ,那么还能填 (P-a_i) 个 1 ,那么如果 (cnt1 leq sum_i(P - a_i)(a_i != 1) + P - 1),则必然可以

反之,若不满足,则将所有数都消耗完依然剩下1,那么必定不合法

得到充要条件后,因为无法同时记录(sum_i a_i mod P)(sum_i (P - a_i)),我们不妨计算钦定总和不为 P 的倍数且不合法的方案数,那么(sum (P -a_i) < n),做一下背包即可,最后用总数((P-1)^{n-1}*(P-2))减去背包方案的 P - 1倍即可(因为我们强行钦定众数为 1 )

3.[AGC043D] Merge Triplets

题意简述:

  • 给定 n ,求长度为 3n 的能被以下方法生成的排列个数。

  • 生成 n 个长度为 3 的数列,使得每个 1 到 3n 中的数恰好被用一次。

  • 生成一个初始为空的数列 P ,重复以下操作 3n 次:

  • 在所有非空数列的开头中选取最小的元素 x 。

  • 把 x 加入到 P 的末尾,并从原数列删去。

(n ≤ 2000)

首先我们思考假设我们已经有数列了该如何生成 P

必然是归并排序,模拟归并排序的过程,就是按照前缀最大值分成若干个长度为1/2/3的段
,然后整段按照前缀最大值从小到大排序

那么我们可以改写题意,称一个排列 P 是合法的,当且仅当它可以被分成若干个长度为 1 / 2 / 3的段,段首单调递增,且一的段个数要大于二的段的个数

倒过来 dp ,设 (dp_{i,j})表示 dp 到 i ,第一个段个数比第二个段多 j

因为最后一段段首必然是全局最大值,根据这个转移即可

总结:

大概分析一下这种条件计数不重不漏的方法(即不包含容斥)

  • 先分析题目性质,思考构造过程

  • 根据构造过程,转化题意,寻找更简洁的充分条件(难点)

  • 根据充分条件 dp (基本功)

分析性质,转化题意这一步在很多其他题目中都有应用,基本功也是必须掌握好的

II.容斥

1.AGC041F

题解:solution

2.ARC096E

套公式仔细分析即可

简单题,但是有一点要注意,只包含空集的集合不是空集

原文地址:https://www.cnblogs.com/y-dove/p/14851822.html