计数合集(Part 2)

Problem A. CF626F Group Projects

\(n\) 个学生,每个学生有一个能力值 \(a_i\)。现在要把这些学生分成一些(任意数量的)组,每一组的“不和谐度”是该组能力值最大的学生与能力值最小的学生的能力值的差。求所有不和谐度之和不超过 \(k\) 的分组方案总数,答案对 \(10^9+7\) 取模。

\(1 \leq n \leq 200\)\(0 \leq k \leq 1000\)\(1 \leq a_i \leq 500\)

解法:

显然能力值顺序与答案无关。从大到小排序后依次确定每个数分到那一组,此时每组的不和谐度是最先加入的数减去最后加入的数。

然后考虑 DP。记 \(f_{i,j,x}\) 表示已经加入了前 \(i\) 个数,现在还有 \(j\) 组可以加入,目前不和谐度和为 \(x\)。可以加入指的是这个组还没有确定不和谐度,即最后加入的数不确定。转移分类讨论,分别是 \(a_i\) 单独一组一个数,或者单独一组一个数但后面还会加入其他数,或者是加入 \(j\) 组中的某组并确定这个组之后不在加入数了,或者后面还会加入。复杂度看似是 \(O(n^2k)\),但是 \(x\) 这一维上限是 \(O(\sum a_i)\) 的,所以复杂度为 \(O(n^2 \sum a_i)\),无法通过。

注意整个过程不对的在于 \(x\) 这一维在决策过程中不一定单调不降,所以无法限制在 \([0,k]\) 中。但是可以发现 \(b_k - b_1 = \sum \limits_{i=1}^{k-1} b_{i+1}-b_i\),于是我们对于每个 \((i,j,x)\),转移到下一步时变为 \((i+1,j',x+j(a_{i}-a_{i+1}))\) 即可。此时 \(x\) 这一维单调不降,故复杂度为 \(O(n^2k)\),对 \(i\) 滚动数组即可通过。

Submission Link.

Problem B. CF2001E1 Deterministic Heap (Easy Version)

题意:

给定一棵 \(n\) 层的满二叉树,节点编号范围为 \([1,2^n-1]\),并且对于任意非叶子节点 \(i\),满足左节点是 \(2i\),右节点是 \(2i+1\),并且每个点有点权 \(a_i\)

定义一次 \(\texttt{pop}\) 操作为如下:

  1. \(v\gets1\)

  2. 重复以下操作直到 \(v\) 是叶子节点:

    a. 对于 \(v\) 的两个子节点,假设点权较大的一个点编号为 \(x\)

    b. \(a_x\gets a_v\)

    c. \(x \gets v\)

  3. \(a_v\gets -1\)

我们定义 \(\texttt{pop}\) 操作是确定的,当且仅当满足上述过程中,\(a_{2v}\neq a_{2v+1}\)

定义一棵满二叉树是大根堆当且仅当对于所有非叶子节点 \(v\) 满足 \(a_v\ge a_{2v}\)\(a_v\ge a_{2v+1}\)

定义一个大根堆是 \(\texttt{pop}\) 操作确定的当且仅当第一次 \(\texttt{pop}\) 操作时 \(\texttt{pop}\) 操作是确定的。

初始时,\(a_v=0\),定义给一个节点 \(x\) 操作一次为把 \(1\rightsquigarrow x\) 路径上所有点点权加上 \(1\),并求出满足恰好操作 \(k\) 次后,不同的 \(\texttt{pop}\) 操作确定的大根堆的数量,模上 \(P\)

多测,\(T \leq 500\)\(1 \leq \sum n, \sum k \leq 500\)\(10^8 \leq P \leq 10^9\)\(P\) 是质数。

解法:

一眼题。

考虑 DP,记 \(f_{i,j}\) 表示高度为 \(i\) 的满二叉树操作 \(j\) 次且 \(\texttt{pop}\) 操作确定的方案数,\(g_{i,j}\) 同理,但是不要求 \(\texttt{pop}\) 操作确定。转移是卷积。直接做复杂度 \(O(nm^2)\),可以通过。NTT 可以做到 \(O(nm \log m)\)

Submission Link.

Problem C. Floyd

题意:

一般来讲 \(O(n^3)\) 求无向图任意两点连通性的算法都用 Floyd 实现,示例代码如下:

void OldFloyd(int n){
    for(int k=1; k<=n; k++){
        for(int i=1; i<=n; i++) if(G[i][k]){
            for(int j=1; j<=n; j++) if(G[k][j]){
                G[i][j] = 1;
            }
        }
    }
}

如果 \(n\) 比较大且执行 Floyd 的次数较多,那么容易超时(小 C 不知道可以用 bitset 优化做到 \(O(\frac{n^3}{w})\)

所以小 C 想出来个奇技淫巧,他限制了 Floyd 的轮数,只让它做 \(m\) 轮,这样复杂度就是 \(O(n^2 \cdot m)\) 的,示例代码如下:

void NewFloyd(int n, int m){
    for(int k=1; k<=m; k++){
        for(int i=1; i<=n; i++) if(G[i][k]){
            for(int j=1; j<=n; j++) if(G[k][j]){
                G[i][j] = 1;
            }
        }
    }
}

这样的做法可以在某种程度上优化求连通性的效率,但是可能会出错,小 C 现在想知道,假如现在等概率随机生成一张 \(n\) 个点的简单无向图(即对于每对 \((i, j)\) \((i < j)\)\(g[i][j]\)\(g[j][i]\)\(\dfrac{1}{2}\) 的概率同时为 1,否则同时为 0。注意:这里我们默认认为对于任意的 \(i\) 都满足 \(g[i][i] = 1\)),并经上述代码一轮 \(m\) 轮 Floyd 后,得到的结果完全正确的概率是多少(即执行两份代码的得到的 \(G\) 数组完全相同),你只需要输出这个概率对大质数 \(p\) 取模后的结果即可。

\(1 \leq n, m \leq 150\)\(10^8 < p < 1.01 \times 10^9\)\(p\) 是质数,\(2\) 秒。

解法:

好题。

求概率等价于求方案数。

容易发现进行 \(m\) 轮 Floyd 本质求出的 \(G_{i,j}\) 其实是 \(i\)\(j\) 是否存在一条路径,路径上除了端点的点编号最大值不超过 \(m\)

首先求出 \(h_i\) 表示 \(i\) 个点的无向简单连通图方案数。这个是简单的。

其次,考虑求 \(g_{i,j}\) 表示 \(n=i,m=j\) 的无向简单连通图方案数,转移考虑将 \(\leq j\) 的点与 \(>j\) 的点分开。然后考虑 \(>j\) 的所有点都要往 \(\leq j\) 的点构成的连通图中连至少一条边。这部分是容易转移的。

接着考虑求 \(f_{i,j}\) 表示 \(n=i,m=j\) 的答案。和 \(g\) 的区别在于不要求连通。转移考虑常见方法,枚举点 \(i\) 所在连通块大小。但是我们还需要枚举这个连通块中有多少点编号 \(<j\),总复杂度 \(O(n^4)\),适当卡常即可通过。

Code.

代码中 \(f\)\(g\) 是反的。

Problem D. CF2001E2 Deterministic Heap (Hard Version)

题意:

定义一个为一棵树高为 \(n\),点数为 \(2^n-1\) 的满二叉树,点权序列为 \(\{a\}\),对于每一个非叶子节点 \(i(1 \le i \le 2^{n-1}-1)\),其儿子应为 \(2i\)\(2i+1\),且满足 \(a_i \ge \max(a_{2i}, a_{2i+1})\)

一次删除操作的伪代码如下:

  1. 初始令 \(v=1\)
  2. 执行 \(a_v \gets \max(a_{2v},a_{2v+1})\),并令 \(v\)\(a_{2v},a_{2v+1}\) 中较大者的下标(若相等则认为这次删除操作不确定\(v\) 变为 \(2v\)\(2v+1\) 中任意一个)。
  3. \(2v+1 \le 2^{n}-1\),返回第 2 条。
  4. 执行 \(a_v \gets -1\)

定义一个堆是确定的,当且仅当执行两次删除操作的过程中,不存在不确定的操作。

定义一个堆是可构造的,当且仅当对于给定常数 \(k\),一个堆的点权序列可以通过以下方式构造出:

  • 初始所有 \(a_i=0\)。执行 \(k\) 次操作,每次任选一个点 \(1 \le x \le 2^n-1\),将根节点到 \(x\) 路径上所有的点权加 \(1\)

\(t\) 次询问,每次给出 \(n,k,p\),求有多少个树高为 \(n\)可构造的堆是确定的,答案对 \(p\) 取模。

\(t \le 50\)\(\sum n \le 100\)\(\sum k \le 500\)\(10^8 \le p \le 10^9\)\(p\) 是质数。

解法:

对于 E1,题意区别在于确定的堆只需要满足一次操作确定即可。其简略做法是记 \(f_{i,j}\) 表示深度为 \(i\) 的二叉树,进行了 \(j\) 次操作构成的确定堆方案数,以及 \(g_{i,j}\) 表示堆不需要确定的方案数。

对于 E2,考虑如何刻画操作两次。可以发现两次操作的第一个走向不同位置只依赖于另一个方向的两个儿子点权最大值。考虑记 \(h_{i,j,k}\) 表示深度为 \(i\) 的堆,进行了 \(j\) 次操作,两个儿子点权最大值为 \(k\),且可以进行一次操作的方案数。\(s_{i,j,k}\) 表示可以进行两次的方案数。可以发现转移只需要枚举左儿子和右儿子点权,维护前缀和即可。为了更加方便可以直接将状态变为儿子最大值 \(\leq k\),复杂度 \(O(nk^2)\),可以通过。

Submission Link.

Problem E. CF1466H Finding satisfactory solutions

题意:

\(n\) 个顾客与 \(n\) 个物品,每个顾客有一个排列 \(b_i\) 表示他对物品喜好程度的排名。

你有一个物品分配方案的排列 \(a\),表示 \(i\) 号顾客拿到第 \(a_i\) 个物品。

称一个分配方案 \(a\) 是好的,当且仅当不存在一个非空集合 \(S\),使得存在一个分配方案 \(a'\) 满足:

  1. \(\forall i \in S, a'_i \in S\)
  2. \(\forall i \in S\),第 \(i\) 个顾客相对 \(a_i\) 更喜欢 \(a'_i\)(不要求严格更喜欢 \(a'_i\),即 \(a_i\) 可以等于 \(a'_i\)
  3. \(\exists i \in S\),第 \(i\) 个顾相对 \(a_i\) 严格更喜欢 \(a'_i\)

输入物品分配方案的排列 \(a_1,a_2,\cdots,a_n\),请求出有多少种不同的 \(\{b_1,b_2,\cdots,b_n\}\) 排列组使得分配方案 \(a\) 是好的。可以证明对于任意一个 \(b\),都存在唯一的好排列 \(a\)

\(n\le 40\),答案对 \(10^9+7\) 取模。

解法:

首先考虑为什么对于任意一个 \(b\),都仅存在唯一的 \(a\)

考虑构建有向图,对于每个 \(i\),连边 \(i \rightarrow b_{i,1}\),意思是每个点向其最喜欢的物品连边。显然图是一个内向基环树森林。不难证明每个环都是要取的,也就是环上的人获得的物品都是其最喜欢的物品。然后将环上点删去,对剩下点继续建图,每个人向第二喜欢的物品编号连边,以此类推。显然对应的好序列唯一确定。

考虑排列 \(a\) 构成的图,连边 \(i \rightarrow a_i\),每个环都是我们生成过程中基环树上的一个环。继续考虑每个人的 \(b\) 怎么确定。我们在 \(a\) 的排列构成的图基础上,对于每个点 \(i\),将其喜爱度比 \(a_i\) 更高的连边,也就是向对应的 \(b\) 序列中 \(a_i\) 前面的点连边。不难发现新的图不能存在包含新的边的环。

将所有环缩点,新的图是一个 DAG。

考虑新图对应的 \(b\) 数量,记 \(deg_i\) 表示 \(i\) 的出度,则对应 \(b\) 数量为 \(\prod \limits_{i} deg_i!(n-deg_i-1)!\)。分别是 \(i\) 的喜爱排列中 \(a_i\) 前后的排列方案数。

这样问题不弱于 DAG 计数,根据 DAG 可以通过每次删去入度为 \(0\) 的点最终变为空图,可以设计一个状压 DP,记 \(f_S\) 表示 \(S\) 子集生成的 DAG 排列对应的 \(b\) 数量之和,转移考虑枚举入度为 \(0\) 的点的一个子集然后子集反演,这样复杂度为 \(O(3^c)\)\(c\)\(a\) 的环数量,无法通过。

进一步,考虑图中存在很多长度相同的环,记状态 \((c_1,c_2,\cdots,c_n)\) 表示每种长度的环的个数,这样状态数不超过 \(1440\),转移直接枚举 \(c'_i \leq c_i\) 的子集,算贡献时要加一个组合数。

Submission Link.

Problem F. CF1530F Bingo

题意:

给定 \(n\) 和一个 \(n \times n\) 方阵 \(p_{1,1},p_{1,2},\cdots,p_{n,n}\)。考虑一个 \(n \times n\)\(\texttt{01}\) 矩阵 \(a\)\(a_{i,j}\)\(p_{i,j}\) 的概率为 \(1\),否则为 \(0\)。求至少存在一行或一列或主对角线或副对角线全为 \(1\) 的概率。答案对质数 \(31607\) 取模。

\(2 \leq n \leq 21\)\(7\) 秒,\(512\) MB。

解法:

对角线并不特别,假设对角线是一个特殊的列。

首先变为求每一行列与对角线都存在 \(0\) 的概率。

直接容斥,我们可以得到一个时间复杂度不低于 \(O(2^{2n})\),无法通过。

一个做法是直接 DP。记 \(f_{i,S}\) 表示前 \(i\) 行,不存在全为 \(1\) 的行,目前每列是否有 \(0\) 的二进制状态为 \(S\)。可以发现转移是或卷积形式,使用 FWT 可以在 \(O(2^nn^2)\) 复杂度内解决此题,若想通过可能需要一些卡常手法。

另一个想法是,容斥做法复杂度瓶颈在于行列对角线总数较大,可以考虑仅对一部分容斥,比如列与对角线,对于另一部分,直接要求不存在为 \(1\) 的行。枚举列与对角线的全 \(1\) 子集后,矩阵有些位置要求必为 \(1\)。然后枚举每一行,第 \(i\) 行,可以算出这行中没有要求的位置全都为 \(1\) 的概率乘积 \(p\),显然直接 \(ans \gets ans \times (1-p)\) 即可。直接做复杂度仍然是 \(O(2^nn^2)\),预处理后即可做到 \(O(2^nn)\)

Submission Link.

posted @ 2024-12-13 18:31  HappyBobb  阅读(36)  评论(0)    收藏  举报