[容斥][单调栈优化dp] Codeforces 1591F Non-equal Neighbours

题目大意

给定一个长为 \(n\) 的数组 \(\{a_n\}(1\leq a_i\leq 10^9)\),需要计算出数组 \(\{b_n\}\) 的方案数,使得 \(1\leq b_i \leq a_i (1\leq i\leq n)\)\(b_i\neq b_{i+1}(1\leq i\leq n-1)\)。方案数模 \(998244353\)

题解

考虑容斥原理,设 \(f(x)\) 表示至少有 \(x\)\(b_i,b_{i+1}\) 相等的方案数。则 \(ans=\sum_{i=0}^{n-1} f(i)\times(-1)^i\)

考虑到使得 \(x\)\(b_i,b_{i+1}\) 相等,相当于把 \(\{b_n\}\) 分成 \(n-x\) 段,每一段内的 \(b_i\) 都相等。

\(f[i]\) 表示满足条件的 \(\{b_n\}\) 的长为 \(i\) 的前缀的方案数,我们可以枚举前 \(i\) 个数的一个后缀,使这个后缀里的所有数相等。则有

\[f[i]=\sum_{j=0}^{i-1} (-1)^{i-j-1}\times f[j]\times \min_{k=j+1}^i \{ a_k \}\\ =(-1)^{i-1}\sum_{j=0}^{i-1}(-1)^j\times f[j]\times \min_{k=j+1}^i \{a_k\} \]

不妨令 \(dp[i]=(-1)^i f(i)\),则有

\[dp[i]=-\sum_{j=0}^{i-1} dp[j]\times \min_{k=j+1}^i \{a_k\} \]

可以维护一个从栈底到栈顶单调递增的单调栈来优化到 \(O(n)\)

最后有

\[ans=dp[n]\times (-1)^n \]

Code

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

#define LL long long

template<typename elemType>
inline void Read(elemType& T) {
    elemType X = 0, w = 0; char ch = 0;
    while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
    while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
    T = (w ? -X : X);
}

const LL MOD = 998244353;
LL a[200010], dp[200010], s[200010], pre[200010];
int n, top;

LL pre_sum(int L, int R) { return pre[R] - (L ? pre[L - 1] : 0); }

int main() {
    Read(n);
    for (int i = 1;i <= n;++i)
        Read(a[i]);
    dp[0] = pre[0] = 1;
    LL sum = 0;
    for (int i = 1;i <= n;++i) {
        while (top && a[s[top]] >= a[i]) {
            sum = (sum - a[s[top]] * pre_sum(s[top - 1], s[top] - 1) % MOD) % MOD;
            --top;
        }
        s[++top] = i;
        sum = (sum + a[i] * pre_sum(s[top - 1], s[top] - 1)) % MOD;
        dp[i] = ((MOD - sum) % MOD + MOD) % MOD;
        pre[i] = (pre[i - 1] + dp[i]) % MOD;
    }
    LL ans = dp[n] * (n & 1 ? -1 : 1);
    ans = (ans % MOD + MOD) % MOD;
    printf("%I64d\n", ans);

    return 0;
}
posted @ 2021-12-29 16:15  AE酱  阅读(156)  评论(0编辑  收藏  举报