动态规划、数学

优先考虑强限制,从相邻两人中至少有一个人纯真下手。

设计 $dp_{i,0}$ 为第 $i$ 个人不纯真,并且前 $i$ 个人的状态满足相邻两人至少有一个人纯真的方案数;设计 $dp_{i,1}$ 为第 $i$ 个人纯真,并且前 $i$ 个人同样满足条件的方案数。

状态 $dp_{i,0}$ 要求第 $i-1$ 个人必须纯真,于是有 $dp_{i,0}=dp_{i-1,1}$ 的转移。

状态 $dp_{i,1}$ 可以从 $dp_{i-1,0}$ 和 $dp_{i-1,1}$ 转移,先讨论比较容易的 $dp_{i-1,1}$ 这个来源。

由于第 $i-1$ 个人是纯真的,所以他前面有 $a_{i-1}$ 个人不纯真,同样地第 $i$ 个人前面也有 $a_{i-1}$ 个人不纯真,于是当且仅当 $a_{i} = a_{i-1}$ 时 $dp_{i-1,1}$ 能够转移到 $dp_{i,1}$。

如果第 $i-1$ 个人不纯真,那第 $i-2$ 个人一定纯真,当且仅当 $a_{i} = a_{i-2} + 1$ 时 $dp_{i-1,0}$ 能够转移到 $dp_{i,1}$。边界条件有些麻烦。

先令 $dp_{1,0} = 1$,若 $a_1 = 0$ 则令 $dp_{1,1} = 1$;否则令 $dp_{1,1} = 0$。由于 $dp_{i,1} \ (i \geq 2)$ 的一个转移依赖 $a_{i-2}$ 的值,单独考虑 $dp_{2,1}$ 的转移,如果 $a_2 = 1$ 则可以从 $dp_{1,0}$ 转移,实现中保持 $a_0 = 0$ 后不特判该情况也是正确的

时间复杂度 $O(n)$。

#include<bits/stdc++.h>
using namespace std;
constexpr int mod=998'244'353;
Mint<mod> dp[200'005][2];
int n,a[200'005];
void solution(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    dp[1][0]=1,dp[1][1]=(a[1]==0);
    for(int i=2;i<=n;i++){
        dp[i][0]=dp[i-1][1];
        if(a[i]==a[i-1]) dp[i][1]+=dp[i-1][1];
        if(a[i]==a[i-2]+1) dp[i][1]+=dp[i-1][0];
    }
    cout<<dp[n][0]+dp[n][1]<<'\n';
    for(int i=1;i<=n;i++) dp[i][0]=0,dp[i][1]=0;
}
int T;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--) solution();
    return 0;
}
最后修改:2025 年 02 月 18 日
如果觉得我的文章对你有用,请随意赞赏