https://codeforces.com/contest/2061/problem/C
题目大意
给出 n (1≤n≤2×105) 个人。每个人可以说谎或诚实。诚实的人总说真话,说谎的人可以说真话或者假话。任意两个说谎的人不相邻。每个人 i 做出了如下论断:i 左侧有 ai (0≤ai≤n) 个人说谎。问最多有多少种可能的说谎诚实的组合。结果模 998244353。
简要题解
观察:
- 如果 ai>i 则这个人只能说谎。因为左侧没有足够的人。
- 因为相邻的两个人不能说谎,因此 i−1 或者 i−2 必然是诚实的。
有了这两个观察我们就可以转移了。
设 dph[i] 和 dpl[i] 分别为第 i 个人诚实和说谎的方案数。
i=0 和 i=1 可以特殊处理。
对于其他的 i。如果 i 位置说谎则 i−1 位置必然为诚实,也就是 dpl[i]=dph[i−1]。
如果 a[i]≤i 则:
- i−1 为诚实,则 i 与 i−1 左侧说谎的人数要一致即 a[i]=a[i−1]:dph[i]←dph[i−1]。
- i−1 说谎,则 i−2 诚实,此时 i 比 i−2 多一个说谎的人,即 a[i]=a[i−2]+1:dph[i]←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; }
Next: [CF] D. Kevin and Numbers - IAEPC Preliminary Contest (Codeforces Round 999, Div. 1 + Div. 2)
Gitalking ...