P5664 [CSP-S2019] Emiya 家今天的饭
idea:
先容斥,将原问题转化为总方案减去不合法的方案。用乘法原理快速计算总方案,再寻找到一个漂亮的性质,利用 dp 计算出不合法方案。 dp 进行一步优化,减去无用状态。
简化题意:
有一个 n 行 m 列的矩阵,坐标为 (i,j) 的格子上有 ai,j 个不同的数。
现在取 k 个数满足以下条件:
-
k>0 。
-
每行只取一个数。
-
每列最多取 ⌊2k⌋ 个数。
求方案数。
分析:
第三个条件不好下手,先不考虑。
我们不妨设 si=∑j=1mai,j 。
那么满足前两个条件的方案数显然是
i=1∏n(si+1) −1
可以 O(n⋅m) 处理出 si ,再 O(n) 求出。
接下来考虑第三个条件。
关键的思想:最多只有一列是不合法的 (即有 2⋅(⌊2k⌋+1)>k )。
我们考虑枚举不合法的列。设当前枚举到了第 i 行,不合法的列为 k ,不合法的列选了 j 个数,其他列选了 h 个数。
设 fk,i,j,h 表示第 k 列不合法,前 i 行,不合法的列选了 j 个数,其他列选了 h 个数的方案数。有以下选择:
- 在别的列取数:
fk,i−1,j,h−1⋅(si−ai,h)
- 在不合法列取数:
fk,i−1,j−1,h⋅ai,h
- 当前行不取数:
fk,i−1,j,h
故有转移:
fk,i,j,h=fk,i−1,j,h−1⋅(si−ai,k)+fk,i−1,j−1,h⋅ai,k+fk,i−1,j,h
不合法的方案数为:
k=1∑mj=1∑nh=1∑j−1fn,j,h
时间复杂度 O(m⋅n3) ,可以拿高分。
然而我们发现,具体的 j,h 对我们来说用处不大,我们只关心 j−h 的值。
故可以将状态化为: fk,i,j 表示第 k 列不合法,前 i 行,不合法的列比其他列多选了 j 个数的方案数。
显然 j∈[−n,n] 。有转移:
fk,i,j=fk,i−1,j+1⋅(si−ai,k)+fk,i−1,j−1⋅ai,k+fk,i−1,j
时间复杂度 O(m⋅n2) ,可以通过。