E. Two Editorials
阿新 • • 發佈:2020-11-22
暴力列舉選的區間右端點是 \(O(n^2m)\) 的,考慮優化,對於一個時間段 \(l, r\) 當選擇講題的區間右端點為 \(x\),
獲得價值為 \(v\),顯然 \(v\) 先隨著 \(x\) 遞增,然後不變,最後在遞減。
考慮計算出 \(f_{i,j}\) 表示選取區間兩個端點為 \(i,j\) 時,i 所產生的貢獻,規定當 \(i < j\) 並且 \(v_i < v_j\) 時,在 \(i\) 出計算,否則在 \(j\) 出計算。
然後對於每個 \(i\),\(v\) 比它小的 \(j\) 是連續的兩端,差分即可。
最後計算 \(f_{i,j} + f_{j,i}\) 的最大值即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i = (a); i <= (b); i++) #define per(i, a, b) for (int i = (a); i >= (b); i--) #define fi first #define se second const int N = 2005, inf = 0x3f3f3f3f, mod = 1e9 + 7; typedef pair <int, int> P; typedef long long LL; int n, m, l[N], r[N], k, v[N], f[N][N], ans; int calc_(int x, int y, int i) { return max(0, min(y, r[i]) - max(x, l[i]) + 1); } int main() { scanf("%d%d%d", &n, &m, &k); rep (i, 1, m) { scanf("%d%d", &l[i], &r[i]); rep (j, k, n) v[j] = calc_(j - k + 1, j, i); int top = k; while (v[top] <= v[top + 1] && top < n) top++; int pos = n + 1; rep (j, k, top) { f[j][k] += v[j], f[j][j + 1] -= v[j]; while (v[pos - 1] < v[j] && pos > top) pos--; f[j][pos] += v[j], f[j][n + 1] -= v[j]; } pos = k - 1; per (j, n, top + 1) { f[j][j] += v[j], f[j][n + 1] -= v[j]; while (v[pos + 1] <= v[j] && pos < top) pos++; f[j][pos + 1] -= v[j], f[j][k] += v[j]; } } rep (i, k, n) rep (j, k, n) f[i][j] += f[i][j - 1]; rep (i, k, n) rep (j, k, n) ans = max(ans, f[i][j] + f[j][i]*(i != j)); printf("%d\n", ans); }