[CF] C. Kevin and Puzzle - IAEPC Preliminary Contest (Codeforces Round 999, Div. 1 + Div. 2)
Solutions Codeforces 动态规划 Med-
Lastmod: 2025-01-20 周一 23:12:56

https://codeforces.com/contest/2061/problem/C

题目大意

给出 $n \ (1 \le n \le 2 \times 10^5)$ 个人。每个人可以说谎或诚实。诚实的人总说真话,说谎的人可以说真话或者假话。任意两个说谎的人不相邻。每个人 $i$ 做出了如下论断:$i$ 左侧有 $a_i \ (0 \le a_i \le n)$ 个人说谎。问最多有多少种可能的说谎诚实的组合。结果模 $998244353$。

简要题解

观察:

  1. 如果 $a_i > i$ 则这个人只能说谎。因为左侧没有足够的人。
  2. 因为相邻的两个人不能说谎,因此 $i - 1$ 或者 $i - 2$ 必然是诚实的。

有了这两个观察我们就可以转移了。

设 $dph[i]$ 和 $dpl[i]$ 分别为第 $i$ 个人诚实和说谎的方案数。

$i = 0$ 和 $i = 1$ 可以特殊处理。

对于其他的 $i$。如果 $i$ 位置说谎则 $i - 1$ 位置必然为诚实,也就是 $dpl[i] = dph[i - 1]$。

如果 $a[i] \le i$ 则:

  1. $i - 1$ 为诚实,则 $i$ 与 $i - 1$ 左侧说谎的人数要一致即 $a[i] = a[i - 1]$:$dph[i] \gets dph[i - 1]$。
  2. $i - 1$ 说谎,则 $i - 2$ 诚实,此时 $i$ 比 $i - 2$ 多一个说谎的人,即 $a[i] = a[i - 2] + 1$:$dph[i] \gets dph[i - 2]$。

最终答案就是 $dph[n - 1] + dpl[n - 1]$。

(虽然只是个 C 题,但是感觉真没那么简单)

复杂度

$T$:$O(n)$

$S$:$O(n)$

代码实现

#include <bits/stdc++.h>
using namespace std;

int io_=[](){ ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();

using LL = long long;
using ULL = unsigned long long;
using LD = long double;
using PII = pair<int, int>;
using VI = vector<int>;
using MII = map<int, int>;

template<typename T> void cmin(T &x,const T &y) { if(y<x) x=y; }
template<typename T> void cmax(T &x,const T &y) { if(x<y) x=y; }
template<typename T> bool ckmin(T &x,const T &y) { 
    return y<x ? (x=y, true) : false; }
template<typename T> bool ckmax(T &x,const T &y) { 
    return x<y ? (x=y, true) : false; }
template<typename T> void cmin(T &x,T &y,const T &z) {// x<=y<=z 
    if(z<x) { y=x; x=z; } else if(z<y) y=z; }
template<typename T> void cmax(T &x,T &y,const T &z) {// x>=y>=z
    if(x<z) { y=x; x=z; } else if(y<z) y=z; }

// mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
// mt19937_64 rnd_64(chrono::system_clock::now().time_since_epoch().count());
template<long long Mo=998244353> struct ModInt {
  static long long MO;
  static void setMo(long long mo) { MO = mo; }
  long long x;
  ModInt(long long x=0) : x(x){ norm(); }
  friend istream &operator>>(istream& in, ModInt &B) { in>>B.x; return in; }
  friend ostream &operator<<(ostream& out, const ModInt &B) { 
    out<<B.x; return out; }
  // ModInt operator=(int x_) { x=x_; norm(); return *this; }
  void norm() { x = (x%MO + MO) % MO; }
  long long get() { return x; }

  ModInt operator-() const { return ModInt(MO - x); }
  ModInt operator+=(const ModInt &B) { x+=B.x; if(x>=MO) x-=MO; return *this; }
  ModInt operator-=(const ModInt &B) { x-=B.x; if(x<0) x+=MO; return *this; }
  ModInt operator*=(const ModInt &B) { x=x*B.x%MO; return *this; }
  ModInt operator+(const ModInt &B) const { ModInt ans=*this; return ans+=B; }
  ModInt operator-(const ModInt &B) const { ModInt ans=*this; return ans-=B; }
  ModInt operator*(const ModInt &B) const { ModInt ans=*this; return ans*=B; }
  ModInt operator^(long long n) const  {
    ModInt a=*this; ModInt ans(1);
    while(n) { if(n&1) ans*=a; a*=a; n>>=1; }
    return ans;
  }
  ModInt inv() const { return (*this)^(MO-2); } // if MO is prime
  ModInt operator/=(const ModInt &B) { (*this)*=B.inv(); return *this; }
  ModInt operator/(const ModInt &B) const { ModInt ans=*this; return ans/=B; }

  bool operator<(const ModInt &B) const { return x<B.x; }
  bool operator==(const ModInt &B) const { return x==B.x; }
  bool operator!=(const ModInt &B) const { return x!=B.x; }
};
template<long long Mo> long long ModInt<Mo>::MO = Mo;
typedef ModInt<998244353> Mint;
// typedef ModInt<1'000'000'007> Mint;
/*
---------1---------2---------3---------4---------5---------6---------7---------
1234567890123456789012345678901234567890123456789012345678901234567890123456789
*/


void solve() {
  int n; cin >> n;
  vector<int> a(n);
  for (int& i : a) cin >> i;

  vector<Mint> dph(n);
  vector<Mint> dpl(n);

  if (a[0]) {
    dpl[0] = 1;
  } else {
    dpl[0] = dph[0] = 1;
  }

  for (int i = 1; i < n; i++) {
    if (a[i] > i) { // only can be liar
      dpl[i] = dph[i - 1];
    } else {
      // liar
      dpl[i] = dph[i - 1];

      // honest
      if (i == 1) {
        if (a[i]) {
          dph[i] = 1;
        } else {
          dph[i] = dph[i - 1];
        }
      } else {
        if (a[i] == a[i - 1]) {
          dph[i] += dph[i - 1];
        }
        if (a[i] == a[i - 2] + 1) {
          dph[i] += dph[i - 2];
        }
      }
    }
  }

  Mint ans = dpl[n - 1] + dph[n - 1];
  cout << ans << '\n';
}

int main() {
  int t = 1; 
  cin >> t;
  while (t--) {
    solve();
  }
  return 0;
}
Prev: [CF] B. Kevin and Geometry - IAEPC Preliminary Contest (Codeforces Round 999, Div. 1 + Div. 2)
Next: [CF] D. Kevin and Numbers - IAEPC Preliminary Contest (Codeforces Round 999, Div. 1 + Div. 2)