专栏文章

P7074 [CSP-J2020] 方格取数

P7074题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@miqoapat
此快照首次捕获于
2025/12/04 08:03
3 个月前
此快照最后确认于
2025/12/04 08:03
3 个月前
查看原文

思路:

考虑动态规划算法,定义 dpi,jdp_{i, j} 表示恰好走到第 ii 列的第 jj 个位置(即之前没有在第 ii 列走过,是由 i1i - 1 列直接走过来的)的最大方案数。
然后转移,枚举是由 i1i - 1 列的第 kk 个走过来的:
dpi,j=max(maxk=1jdpi1,k+si1,jsi1,k1,maxk=jndpi1,k+si1,ksi1,j1)dp_{i, j} = \max\Big( \max_{k = 1}^j dp_{i -1, k} + s_{i - 1, j} - s_{i - 1, k - 1}, \max_{k = j}^n dp_{i - 1, k} + s_{i - 1, k} - s_{i - 1, j - 1} \Big)
其中 si,js_{i, j} 表示第 ii 列前 jj 个数的和。
朴素转移是 O(N3)O(N^3) 的(但是好像可以直接过)。
考虑优化,注意到我们要查询一个前缀 dpi1,ksi1,k1dp_{i - 1, k} - s_{i - 1, k - 1} 与一个后缀 dpi1,k+si1,kdp_{i - 1, k} + s_{i - 1, k} 的最大值。
直接开一个 fi,j,gi,jf_{i ,j}, g_{i, j} 维护即可。
时间复杂度优化至 O(N2)O(N^2)

完整代码:

CPP
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define Add(x, y) (x + y >= mod) ? (x + y - mod) : (x + y)
#define lowbit(x) x & (-x)
#define pi pair<ll, ll>
#define pii pair<ll, pair<ll, ll>>
#define iip pair<pair<ll, ll>, ll>
#define ppii pair<pair<ll, ll>, pair<ll, ll>>
#define ls(k) k << 1
#define rs(k) k << 1 | 1
#define fi first
#define se second
#define full(l, r, x) for(auto it = l; it != r; ++it) (*it) = x
#define Full(a) memset(a, 0, sizeof(a))
#define open(s1, s2) freopen(s1, "r", stdin), freopen(s2, "w", stdout);
#define For(i, l, r) for(register int i = l; i <= r; ++i)
#define _For(i, l, r) for(register int i = r; i >= l; --i)
using namespace std;
using namespace __gnu_pbds;
typedef __int128 __;
typedef long double lb;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
bool Begin;
const int N = 1010; 
inline ll read(){
    ll x = 0, f = 1;
    char c = getchar();
    while(c < '0' || c > '9'){
        if(c == '-')
          f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9'){
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}
inline void write(ll x){
	if(x < 0){
		putchar('-');
		x = -x;
	}
	if(x > 9)
	  write(x / 10);
	putchar(x % 10 + '0');
}
ll ans = -1e18;
int n, m;
int a[N][N];
ll s[N][N], dp[N][N], f[N][N], g[N][N];
bool End;
int main(){
	memset(dp, -0x7f, sizeof(dp));
	memset(f, -0x7f, sizeof(f));
	memset(g, -0x7f, sizeof(g));
	n = read(), m = read();
	for(int i = 1; i <= n; ++i){
		for(int j = 1; j <= m; ++j){
			a[i][j] = read();
			s[j][i] = s[j][i - 1] + a[i][j];
		}
	}
	dp[1][1] = 0, g[1][1] = a[1][1];
	for(int i = 1; i <= n; ++i)
	  f[1][i] = 0;
	for(int i = 2; i <= m; ++i){
		for(int j = 1; j <= n; ++j)
		  dp[i][j] = max(f[i - 1][j] + s[i - 1][j], g[i - 1][j + 1] - s[i - 1][j - 1]);
		for(int j = 1; j <= n; ++j)
		  f[i][j] = max(f[i][j - 1], dp[i][j] - s[i][j - 1]);
		for(int j = n; j >= 1; --j)
		  g[i][j] = max(g[i][j + 1], dp[i][j] + s[i][j]);
	}
	for(int i = 1; i <= n; ++i)
	  ans = max(ans, dp[m][i] + s[m][n] - s[m][i - 1]);
	write(ans);
	cerr << '\n' << abs(&Begin - &End) / 1048576 << "MB";
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...