zoukankan      html  css  js  c++  java
  • [容斥][单调栈优化dp] Codeforces 1591F Nonequal 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;
    }
    
  • 相关阅读:
    读书笔记-编写可读代码的艺术[中]
    读书笔记-编写可读代码的艺术[上]
    读书笔记-编写可读代码的艺术[上]
    单元测试Struts2Spring项目的Action和Service(包含源码)
    单元测试Struts2Spring项目的Action和Service(包含源码)
    单元测试Struts2的Action(包含源码)
    Java实现 LeetCode 223 矩形面积
    Java实现 LeetCode 223 矩形面积
    Java实现 LeetCode 223 矩形面积
    Java实现 LeetCode 222 完全二叉树的节点个数
  • 原文地址:https://www.cnblogs.com/AEMShana/p/15745435.html
Copyright © 2011-2022 走看看