DistinctAdjacent

[ABC307E] Distinct Adjacent

解答1:

我们将圆环上有 \(i\) 个人的情况的答案记为 \(f(i)\)。考虑有 \(i+1\) 个人排成一排的情况,此时答案为 \(M \times (M-1)^i\)。这样的传递方式中,如果是圆环的情况且不满足条件的传递方式只有人 \(i+1\) 和人 \(1\) 的情况不同。因此,这两个人可以视为同一人,这样的传递方式有 \(f(i)\) 种。因此,我们有 \(f(i+1)=M \times (M-1)^i-f(i)\)。这样就解决了这个问题。

代码

解答2:

DP

这道题可以看作是 ABC256G 和 ABC232E 的简化版。

圆环上的DP

对于一排排列的情况,我们可以考虑 DP,定义状态 \(\mathrm{DP}[i][x]\) 表示前 \(i\) 个人已经分配完毕,第 \(i\) 个人手中的数字为 \(x\),并且前 \(i\) 个人中没有相邻的人手中的数字相同的方案数。这样的话,我们只需要考虑第 \(i\) 个人手中的数字和第 \(i-1\) 个人手中的数字是否相同即可。最后的答案就是 \(\sum_{x=0}^{M-1} \mathrm{DP}[N][x]\)

对于围成一圈的情况,我们可以先固定第一个人手中的数字为 \(k\),然后考虑 DP,定义状态 \(\mathrm{DP}_k[i][x]\) 表示前 \(i\) 个人已经分配完毕,第 \(1\) 个人手中的数字为 \(k\),第 \(i\) 个人手中的数字为 \(x\),并且前 \(i\) 个人中没有相邻的人手中的数字相同的方案数。这样的话,我们只需要考虑第 \(i\) 个人手中的数字和第 \(i-1\) 个人手中的数字是否相同即可。最后的答案就是 \(\sum_{k=0}^{M-1} \sum_{x \neq k} \mathrm{DP}_k[N][x]\)

但是,这样的 DP 状态数和转移数都是 \(O(NM^N)\) 的,无法通过本题。因此,我们需要进行状态的优化。注意到,我们只需要知道第 \(i\) 个人手中的数字和第 \(1\) 个人手中的数字是否相同即可,因此我们可以将状态 \(\mathrm{DP}[i][x]\) 中的 \(i\) 去掉,只保留一个布尔值 \(f\) 表示第 \(i\) 个人手中的数字和第 \(1\) 个人手中的数字是否相同。这样的话,状态数就变成了 \(O(N)\),转移数也是 \(O(1)\) 的。最后的答案就是 \(\mathrm{DP}[N][\mathrm{false}]\)

例题:

writer解(C)

另外,我们还可以使用包除原理来求解。注意到,我们需要满足 \(N\) 个条件,即相邻的两个人手中的数字不能相同。我们可以考虑使用包除原理,设 \(S_k\) 表示恰好有 \(k\) 个相邻的人手中的数字相同的方案数,则最终的答案为 \(\sum_{k=0}^N (-1)^k \binom{N}{k} M^{\max(1, N-k)}\)。这个式子的计算量是 \(O(N)\) 的,可以通过本题。

解答3:

答案是 \((-1)^N(M-1)+(M-1)^N\)。可以通过以下几种方法得出:

  1. 包括排斥原理

使用包括排斥原理,可以得出方案数为

\[\sum_{k=0}^N(-1)^k\binom{N}{k}M^{\max\{1,N-k\}} \]

整理得到

\[\begin{aligned} \sum_{k=0}^N(-1)^k\binom{N}{k}M^{\max\{1,N-k\}}&=(-1)^N(M-1)+\sum_{k=0}^N(-1)^k\binom{N}{k}M^{N-k}\\ &=(-1)^N(M-1)+(M-1)^N \end{aligned} \]

  1. DP 的优化

公式解释中的 DP 可以写成矩阵乘法的形式,因为转移不依赖于 \(i\)。具体来说,答案可以表示为

\[a_N=\begin{pmatrix}1&0\end{pmatrix}\begin{pmatrix}M-2&M-1\\1&0\end{pmatrix}^{N-1}\begin{pmatrix}0\\M\end{pmatrix} \]

整理得到 \(a_n=(-1)^n(M-1)+(M-1)^n\)。也可以通过解 \(2\) 阶线性递推式得到这个结果,即

\[\begin{aligned} a_2&=M(M-1)\\ a_3&=M(M-1)(M-2)\\ a_n&=(M-2)a_{n-1}+(M-1)a_{n-2}\ (n\geq4) \end{aligned} \]

以下是一个实现的例子:

#include <bits/extc++.h>
#include <atcoder/modint>

int main() {
    using namespace std;
    int N, M;
    cin >> N >> M;
    atcoder::static_modint<998244353> m = M - 1;
    cout << (m.pow(N) + (N & 1 ? -m : m)).val() << endl;
    return 0;
}
N, M = map(int, input().split())
p = 998244353

print((pow(M - 1, N, p) + pow(-1, N, p) * (M - 1)) % p)
posted @ 2023-06-28 15:48  wscqwq  阅读(18)  评论(0编辑  收藏  举报