DistinctAdjacent

[ABC307E] Distinct Adjacent

解答1:

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

代码

解答2:

DP

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

圆环上的DP

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

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

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

例题:

writer解(C)

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

解答3:

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

  1. 包括排斥原理

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

k=0N(1)k(Nk)Mmax{1,Nk}

整理得到

k=0N(1)k(Nk)Mmax{1,Nk}=(1)N(M1)+k=0N(1)k(Nk)MNk=(1)N(M1)+(M1)N

  1. DP 的优化

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

aN=(10)(M2M110)N1(0M)

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

a2=M(M1)a3=M(M1)(M2)an=(M2)an1+(M1)an2 (n4)

以下是一个实现的例子:

#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)

本文作者:wscqwq

本文链接:https://www.cnblogs.com/wscqwq/p/17511615.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   wscqwq  阅读(22)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起