Codeforces1304F.Animal Observation

分析一下得知是DP问题,时间复杂度符合,设dp[i][j]为从第i天开始,第j个位置能得到的最大值,其有三种转移状态

1.与上一天的选择有重合

2.与上一天的选择没有重合,且上一天的选择在左边

3.与上一天的选择没有重合,且上一天的选择在右边

那么得到转移方程,

1.dp[i][j] = max(dp[i-1][x])(x+k-1与j+k-1有交点)-重复部分

2.dp[i][j] = max(dp[i-1][x])(x+k-1在j的左边)+该次选择得到的数

3.同2

我们预处理前缀和,再在每次dp更新后为下一天的dp更新每个点左边的最大值,复杂度为O(nmk)

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) ((x)&(-x))
typedef long long LL;

const int maxn = 55;
const int maxm = 2e4+5;

int dp[maxn][maxm], C[maxn][maxm], lmax[maxn][maxm], rmax[maxn][maxm];

int getsum(int i, int p1, int p2) {
    return C[i][p2] - C[i][p1-1];
}


void run_case() {
    int n, m, k, val;
    cin >> n >> m >> k;
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j) {
            cin >> val;
            C[i][j] = C[i][j-1] + val;
        }
    for(int i = 1; i <= n; ++i) {
        for(int j = 1; j <= m - k + 1; ++j) {
            val = getsum(i, j, j+k-1) + getsum(i+1, j, j+k-1);
            if(i == 1) {
                dp[i][j] = val;
                continue;
            }
            int mx = 0;
            // intersect part
            for(int l = max(1, j-k+1); l <= min(m-k+1, j+k-1); ++l)
                mx = max(mx, dp[i-1][l]+val-getsum(i, max(l, j), min(j+k-1,l+k-1)));
            dp[i][j] = mx;
            if(j > k) dp[i][j] = max(dp[i][j], lmax[i-1][j-k]+val);
            if(j + k <= m - k + 1) dp[i][j] = max(dp[i][j], rmax[i-1][j+k]+val);
        }
        for(int j = 1; j <= m-k+1; ++j) lmax[i][j] = max(dp[i][j], lmax[i][j-1]);
        for(int j = m-k+1; j >= 1; --j) rmax[i][j] = max(dp[i][j], rmax[i][j+1]);
    }
    cout << *max_element(dp[n]+1, dp[n]+1+m) << "\n";
}
 
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    //cout.setf(ios_base::showpoint);cout.precision(10);
    //int t; cin >> t;
    //while(t--)
    run_case();
    cout.flush();
    return 0;
}
View Code

hard vision就是将k的范围扩大很多,可以用线段树O(nmlogm)或者是单调队列O(nm)来优化区间最值问题,以后再补

猜你喜欢

转载自www.cnblogs.com/GRedComeT/p/12317333.html