题解:P3352 [ZJOI2016] 线段树
biyi_mouse · · 题解
或许更好的阅读体验
首先观察题面,期望乘上
所有我们不妨先把答案的式子写出来,即
然后考虑如何计算
所以我们不妨继续尝试下 DP。容易发现 DP 的阶段应该是操作的次数,记为
到此,我们便顺利地得出状态表示
然后思考转移,这一步比较简单,我们直接给出转移式。
其中
所以
到此我们便得到了
然而我们可以继续优化,注意到在
此时我们再把
此时我们可以发现,对于某个
但这样子初值就不同了,考虑对于
于是我们就优化到了
#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = (a); i <= (b); i ++)
#define fro(i, a, b) for (int i = (a); i >= b; i --)
#define INF 0x3f3f3f3f
#define eps 1e-6
#define lowbit(x) (x & (-x))
#define initrand srand((unsigned)time(0))
#define random(x) ((LL)rand() * rand() % (x))
#define eb emplace_back
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, int> PDI;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); }
return x * f;
}
const int N = 1010, Mod = 1e9 + 7;
int n, q;
int a[N], f[2][N][N], g[N][N], s1[2][N][N], s2[2][N][N];
int add(int a, int b, int c) {
return ((a + b) % Mod + c) % Mod;
}
int mul(int a, int b) {
return 1ll * a * b % Mod;
}
int calc(int x) {
return 1ll * x * (x + 1) / 2;
}
int main() {
cin >> n >> q;
for (int i = 1; i <= n; i ++) cin >> a[i];
a[0] = a[n + 1] = 1e9 + 1;
for (int l = 1; l <= n; l ++) {
int maxx = 0;
for (int r = l; r <= n; r ++) {
maxx = max(maxx, a[r]);
if (l == 1 && r == n) f[0][l][r] = maxx;
else if (a[l - 1] > maxx && a[r + 1] > maxx)
f[0][l][r] = (maxx - min(a[l - 1], a[r + 1]) + Mod) % Mod;
g[l][r] = add(calc(r - l + 1), calc(l - 1), calc(n - r));
}
}
for (int i = 1; i <= q; i ++) {
int now = i & 1, pre = i & 1 ^ 1;
for (int l = 1; l <= n; l ++) {
for (int r = l; r <= n; r ++)
s1[pre][l][r] = (s1[pre][l - 1][r] + mul(f[pre][l][r], l - 1)) % Mod;
for (int r = n; r >= l; r --)
s2[pre][l][r] = (s2[pre][l][r + 1] + mul(f[pre][l][r], n - r)) % Mod;
}
for (int l = 1; l <= n; l ++)
for (int r = l; r <= n; r ++)
f[now][l][r] = add(mul(f[pre][l][r], g[l][r]), s1[pre][l - 1][r], s2[pre][l][r + 1]);
}
for (int i = 1; i <= n; i ++) {
int ans = 0;
for (int l = 1; l <= i; l ++)
for (int r = i; r <= n; r ++)
ans = (ans + f[q & 1][l][r]) % Mod;
cout << ans << " ";
}
return 0;
}