1 条题解

  • 0
    @ 2025-2-2 19:02:13

    考虑 DP。用 fi,0/1f_{i,0/1} 表示前 ii 个人的游戏中,第 ii 个人是诚实者 / 说谎者的方案数。

    首先考虑 fi,1f_{i,1} 如何转移。此时第 ii 个人是说谎者,所以第 i1i-1 个人一定是诚实的。因此 fi,1=fi1,0f_{i,1}=f_{i-1,0}

    然后考虑 fi,0f_{i,0} 如何转移。此时第 ii 个人是诚实者,第 i1i-1 个人有可能说谎,也有可能诚实。所以我们分两种情况:

    • i1i-1 是诚实的,此时要满足的条件是 ai=ai1a_{i}=a_{i-1}。若满足这个条件,则 fi,0+=fi1,0f_{i,0}+=f{i-1,0}
    • i1i-1 是说谎者,则 i2i-2 一定是诚实者。所以此时要满足的条件是 ai=ai2+1a_{i}=a_{i-2}+1。若满足这个条件,则 fi,0+=fi1,1f_{i,0}+=f_{i-1,1}

    所以最终的转移方程为:

    fi,1=fi1,0fi,0+=fi1,0   (ai=ai1)fi,0+=fi1,1   (ai=ai2+1)f_{i,1}=f_{i-1,0}\\ f_{i,0}+=f_{i-1,0}~~~(若a_i=a_{i-1})\\ f_{i,0}+=f_{i-1,1}~~~(若a_i=a_{i-2}+1)\\

    初始化:若 a1=0a_1=0,则第一个人可能是诚实者,也可能是说谎者,所以 f1,0=f1,1=1f_{1,0}=f_{1,1}=1。若 a10a_1\neq 0,则第一个人一定是说谎者,所以 f1,0=0,f1,1=1f_{1,0}=0,f_{1,1}=1

    最终答案为 fn,0+fn,1f_{n,0}+f_{n,1}

    #include<bits/stdc++.h>
    using namespace std;
    #define endl '\n' 
    const int N = 200010, mod = 998244353;
    int n, c, a[N];
    int f[N][2];
    int main()
    {
        freopen("lie.in","r",stdin);
        freopen("lie.out","w",stdout);
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        cin >> n >> c;
        for(int i = 1; i <= n; i++) cin >> a[i];
    
        if(a[1] == 0) f[1][0] = f[1][1] = 1;
        else f[1][0] = 0, f[1][1] = 1;
        
        for(int i = 2; i <= n; i++)
        {
            f[i][1] = f[i - 1][0];
    
            if (a[i - 1] == a[i]) f[i][0] += f[i - 1][0], f[i][0] %= mod;
            if (a[i - 2] + 1 == a[i]) f[i][0] += f[i - 1][1], f[i][0] %= mod;
        }
        cout << (f[n][0] + f[n][1]) % mod;
        return 0;
    }
    

    信息

    ID
    512
    时间
    500ms
    内存
    256MiB
    难度
    8
    标签
    递交数
    29
    已通过
    6
    上传者