CF2021D 题解 | dp
题意
给你一个 \(n\) 行 \(m\) 列的矩阵,要求对于每行选出一个区间 \([l_i, r_i]\),得到 \(\sum _ {j = {l_i}} ^ {r_i} a_{i, j}\) 的权值。
区间之间有限制:
求最大权值。
思路
显然这是一个 dp 题。
考虑朴素的状态设计 \(f_{i, l, r}\) 表示计算了前 \(i\) 行,第 \(i\) 行选区间 \([l, r]\) 的最大权值。
显然状态数 \(O(nm^2)\) 直接倒闭。
我们试图转换题目限制,可以发现,相当于是限制 \(l_{i - 1}, r_{i - 1}\) 至少有一个在区间 \((l_i, r_i)\) 中。
那也就是说,我们没有必要记录左右端点,于是得到状态优化:
\(f_{i, j, 0/1}\) 表示计算前 \(i\) 行,第 \(i\) 行选择的左(\(0\))/ 右(\(1\))端点是 \(j\),此时的最大权值。
可以启发想到这一点的例子:
设 \(i - 1\) 行的左右端点分别是 \(l', r'\),第 \(i\) 行左右端点是 \(l, r\)。
考虑情况 \(l \lt l'\),则 \(r\) 的限制只有 \(r \ge l'\),显然没有必要记录 \(r'\),可以启发优化状态。
接下来就是分类讨论:

case 1: \(l \lt l'\)
此时要求满足 \(r \ge l'\)。
其中 \(calc1(l, r)\) 表示所有区间左端点 \(=l\),右端点 \(\ge r\) 的区间中区间和最大值。
此时,我们可以倒序枚举 \(l\),维护 \(s\) 后缀 \(\max\)(记为 \(mxs\))、转移式中与 \(l'\) 有关的项的后缀 \(\max\) (记为 \(mx\))即可做到每次 \(O(1)\) 更新答案。
具体地,流程如下:
-
倒序枚举 \(l\)
-
将 \(l + 1\) 计算入 \(s\) 的后缀 \(\max\)。(因为限制是 \(l' \gt l\),那么算入 \(mxs\) 的也需要满足 \(j \gt l\),就在枚举到 \(l\) 时加入 \(l + 1\))
-
用 \(f_{i - 1, l + 1, 0} + mxs\) 更新 \(mx\)。(\(l + 1\) 与上一步同理,实际上是把和 \(l'\) 有关的部分一起算)
-
用 \(mx - s_{l - 1}\) 更新 \(f_{i, l, 0}\)(\(- s_{l - 1}\) 和 \(mx\) 一起组成整个转移式)
-
case 2: \(l = l'\)
此时 \(l'\) 并不在 \((l,r)\) 中,于是不能从 \(f_{i - 1, l', 0}\) 转移过来,所以从 \(f_{i - 1, r', 1}\) 转移。
case 3 & 4
同理 case 1 & 2。
记 \(calc2(l,r)\) 表示右端点是 \(r\),左端点 \(\leq l\) 的区间的最大利润。
case 3:
case 4:
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int ui;
#define rep(i, l, r) for(int i = l; i <= r; i++)
#define per(i, l, r) for(int i = l; i >= r; i--)
#define NESTED_MACRO_STR(x) #x
#define MACRO_STR(x) NESTED_MACRO_STR(x)
inline ll read(){
ll res = 0, flg = 1;
char c = getchar();
for(; c > '9' || c < '0'; c = getchar()) if(c == '-') flg = -flg;
for(; c >= '0' && c <= '9'; c = getchar()) res = res * 10 + c - '0';
return res * flg;
}
template <typename T> inline void write(T x, char c = '\n'){
if(x < 0) putchar('-'), x = -x;
static int sta[35]; int top = 0;
do { sta[top++] = x % 10, x /= 10; } while (x);
while (top) putchar(sta[--top] + 48);
putchar(c);
}
void __deb__(const char *s) { cerr << '\n'; }
template <typename T, typename... Ts>
void __deb__(const char *s, T v, Ts... vs){
const char *c = strchr(s, ',');
string name(s, c ? c - s : strlen(s));
if(std::is_floating_point<T>::value) {
cerr << name << " : " << fixed << setprecision(10) << v;
} else {
cerr << name << " : " << v;
}
if(c) { cerr << " | "; __deb__(c + 1, vs...); }
else cerr << '\n';
}
#define deb(...) __deb__(#__VA_ARGS__, __VA_ARGS__)
template <typename T> void chkmx(T &a, T b) { a = (a > b) ? a : b; }
template <typename T> void chkmn(T &a, T b) { a = (a < b) ? a : b; }
template <typename T> T calc_mod(T x, T mod){ while(x < 0) {x += mod;} x %= mod; return x; }
template <typename T> void mod_plus(T &x, T y, T mod) { x = calc_mod(calc_mod(x, mod) + calc_mod(y, mod), mod); }
template <typename T> void mod_sub(T &x, T y, T mod) { x = calc_mod(calc_mod(x, mod) - calc_mod(y, mod), mod); }
// #define FILE_NAME (type your freopen file name here)
const ll inf = 1e18;
void solve_test_case(){
int n = read(), m = read();
vector<vector<ll>> a(n + 5, vector<ll> (m + 5));
vector<vector<ll>> f[2];
f[0] = f[1] = vector<vector<ll>> (n + 5, vector<ll> (m + 5, -inf));
vector<ll> s(m + 5, 0);
rep(i, 1, n){
rep(j, 1, m){
a[i][j] = read();
}
}
rep(j, 1, m){
s[j] = s[j - 1] + a[1][j];
}
ll mxs = -inf, mns = inf;
per(l, m, 1){
chkmx(mxs, s[l]);
f[0][1][l] = mxs - s[l - 1];
}
rep(r, 1, m){
chkmn(mns, s[r - 1]);
f[1][1][r] = s[r] - mns;
}
rep(i, 2, n){
vector<ll> s(m + 5, 0);
rep(j, 1, m){
s[j] = s[j - 1] + a[i][j];
}
ll mx, mxs, mns;
mx = mxs = -inf, mns = inf;
per(l, m, 1){
if(l + 1 <= m) chkmx(mxs, s[l + 1]);
chkmx(mx, f[0][i - 1][l + 1] + mxs);
chkmx(f[0][i][l], mx - s[l - 1]);
}
mx = mxs = -inf, mns = inf;
per(l, m, 1){
if(l + 1 <= m) chkmx(mxs, s[l + 1]);
chkmx(mx, f[1][i - 1][l] + mxs);
chkmx(f[0][i][l], mx - s[l - 1]);
}
mx = mxs = -inf, mns = inf;
rep(r, 1, m){
if(r - 2 >= 0) chkmn(mns, s[r - 2]);
chkmx(mx, f[1][i - 1][r - 1] - mns);
chkmx(f[1][i][r], mx + s[r]);
}
mx = mxs = -inf, mns = inf;
rep(r, 1, m){
if(r - 2 >= 0) chkmn(mns, s[r - 2]);
chkmx(mx, f[0][i - 1][r] - mns);
chkmx(f[1][i][r], mx + s[r]);
}
}
ll ans = -inf;
rep(i, 1, m){
chkmx(ans, max(f[0][n][i], f[1][n][i]));
}
write(ans);
}
signed main(){
#ifdef FILE_NAME
freopen((string(MACRO_STR(FILE_NAME)) + ".in").c_str(), "r", stdin);
freopen((string(MACRO_STR(FILE_NAME)) + ".out").c_str(), "w", stdout);
#endif
int Test_case_num = read();
while(Test_case_num--) solve_test_case();
return 0;
}

浙公网安备 33010602011771号