「2021-09-12 联考」I love random (C)

考虑DP,记\(f(i,j)\)表示第\(i\)个数最终是\(j\)的方案数。
那么考虑这个点的转移,它可能被前后的数覆盖,也可能覆盖前后的数。
为了方便,不妨只考虑每个点往前覆盖(或不动),以及被前面覆盖的情况。
首先考虑往前覆盖,那么它最多覆盖到单调栈中上一个元素,记那么位置为\(p\),那么有转移,\(f(i,A_i)\gets\sum_{j=p}^{i-1}\sum_{k=1}^Nf(j,k)\),同时更新一下这些点最终为\(A_i\)是的dp值。
接着考虑它被覆盖的情况,它一定只能被单调栈中的元素覆盖。那么考虑它前面的一个位置,若\(i\)最终为\(j\),那么前一个数一定只能填\(\leq j\)的数字,转移一下即可。
因为这题还卡空间,稍微优化一下可以做到时间复杂度\(\mathcal O(N^2)\),空间复杂度\(\mathcal O(N)\)。
Code
#include <bits/stdc++.h>
int main(void) {
freopen("C.in", "r", stdin), freopen("C.out", "w", stdout);
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
const int P = 1E9 + 7;
auto incr = [&](int& a, int b) {
a -= (a += b) >= P ? P : 0;
};
int N;
std::cin >> N;
std::vector <int> A(N + 1, 0);
for (int i = 1; i <= N; ++i)
std::cin >> A[i];
std::vector <int> dp(N + 1, 0), eva(N + 1, 0), _(N + 1, 0), Q(N, 0), __(N + 1, 0);
int top = 0;
Q[top] = dp[0] = dp[1] = 1;
for (int i = A[1]; i <= N; ++i)
eva[i] = 1;
for (int i = 2; i <= N; ++i) {
_[A[i]] = dp[i - 1];
while ((~top) && A[Q[top]] > A[i])
--top;
Q[++top] = i;
for (int j = 0; j < top; ++j)
_[A[Q[j]]] = eva[A[Q[j]]];
eva = _, _ = __;
int k = 0;
for (int j = i - 1; j; --j) {
if (A[j] < A[i]) {
k = j;
break;
}
incr(eva[A[i]], dp[j - 1]);
}
for (int j = k + 1; j < i; ++j) {
incr(dp[j], dp[j - 1]);
}
for (int j = 1; j <= N; ++j)
incr(eva[j], eva[j - 1]);
dp[i] = eva[N];
}
std::cout << dp[N] << '\n';
return 0;
}

浙公网安备 33010602011771号