Codeforces Round #620 F2. Animal Observation (hard version) (dp + 线段树)

Codeforces Round #620 F2. Animal Observation (hard version) (dp + 线段树)

题目链接

题意

给定一个nm的矩阵,每行取2k的矩阵,求总共矩阵里的数的和最大值,重复取到的数不算

题解

dp[i]表示当前行从第i个数开始取矩阵的最大值

dp[i] = 上一行中最大数 + 当前行第i个数到第i+k-1个数的和 - 当前行重复的 + 下一行第i个数到第i+k-1个数的和

用线段树维护 上一行中最大数 + 当前行第i个数到第i+k-1个数的和 - 当前行重复的

从当前行第1个数开始对上一行的dp值做上述操作,每当往右移一个数做dp,只要做当前区间的头尾删除和增加操作,具体操作看代码

#include <bits/stdc++.h>
using namespace std;
const int N = 50010;
int tree[N*4], upd[N*4], dp[N], a[101][N], pre[101][N];
void build(int x,int l,int r)
{
    if (l == r) tree[x] = dp[l];
    else 
    {
        int mid = (l + r) >> 1;
        build(x*2, l, mid);
        build(x*2+1, mid + 1, r);
        upd[x] = 0;
        tree[x] = max(tree[x*2], tree[x*2+1]);
    }
}
void add(int x, int l,int r,int ll,int rr,int v)
{
    if (ll > rr) return;
    if (ll <= 0) return;
    if (l == r)
    {
        tree[x] += v;
        return;
    }
    if (ll <= l && r <= rr)
    { 
        upd[x] += v;
        tree[x] += v;
    }
    else 
    {
        tree[x * 2] += upd[x];
        upd[x * 2] += upd[x];
        tree[x * 2 + 1] += upd[x];
        upd[x * 2 + 1] += upd[x];
        upd[x] = 0;
        int mid = (l + r) >> 1;
        if (ll <= mid) add(x * 2, l, mid, ll, rr, v);
        if (rr > mid) add(x * 2 + 1, mid + 1, r, ll, rr, v);
        tree[x] = max(tree[x * 2], tree[x * 2 + 1]);
    }
}
int main()
{
    int n, m, k;
    cin >> n >> m >> k;
    k--;//j + k - 1 -> j + k,纯粹是懒
    for (int i = 1; i <= n; i++)
     for (int j = 1; j <= m; j++)
     {
         cin >> pre[i][j];
         a[i][j] = pre[i][j];
         pre[i][j] += pre[i][j - 1];
     }
    for (int j = 1; j + k <= m; j++)
     {
         dp[j] = pre[1][j + k] - pre[1][j - 1] + pre[2][j + k] - pre[2][j - 1];
     }
    for (int i = 2; i <= n; i++)
     {
         build(1,1,m-k);
         for (int j = 1; j <= k + 1; j++) add(1,1,m-k,j+1,m-k,a[i][j]);//对上一行的dp值增加没有重复的第一个区间的值
         dp[1] = tree[1] + pre[i+1][k+1];
         for (int j = 2; j + k <= m; j++)
         {
             add(1,1,m-k,1,j-1,a[i][j+k]);
             add(1,1,m-k,j+k+1,m-k,a[i][j+k]);//对没有和a[i][j+k]重复的dp值加上a[i][j+k]
             add(1,1,m-k,j,m-k,-a[i][j-1]);
             add(1,1,m-k,1,j-k-2,-a[i][j-1]);//对增加过a[i][j-1]的dp减去a[i][j-1]
             dp[j] = tree[1] + pre[i+1][j + k] - pre[i+1][j-1];
         }
     }
     build(1,1,m-k);
     cout << tree[1] << endl;
    // system("pause");
}

猜你喜欢

转载自www.cnblogs.com/7osen/p/12316016.html
今日推荐