[容斥][单调栈优化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;
}