zoukankan      html  css  js  c++  java
  • F、Animal Observation (DP + 线段树 + 滑动窗口)

    题目:传送门

    题意: 有n天,m个区域,第 i 天第 j 个区域有 a[ i ][ j ] 个动物, 然后, 你可以在放一个 2 * k 的矩阵, 问你 n 天能够观察到的动物最多是多少。 若两个矩阵都包含了 a[ i ][ j ],那 a[ i ][ j ]  只算一次。

        ≤ ≤ 50, ≤ ≤ 2 * 10^4 ≤ ≤ m

          

    解: 这里有个视频讲解的, 想看视频讲解可以

        设dp[ i ][ j ] 表示第 i 天,观察左上角为 (i, j)的 2 * k 矩阵区域能观察到的动物总数。

        然后再开个 sum[ i ][ j ] 表示 第 i 天 前 j 块区域的总动物数。 也就是前缀和。

        若不考虑重合只算一次这个条件。 那么有转移方程

        dp[ i ][ j ] = max({ dp[ i - 1 ][ 1 ] , dp[ i - 1 ][ 2 ] ........ dp[ i - 1 ][ m - k + 1] }) + sum[ i ][ j + k - 1 ] - sum[ i ][ j - 1 ] + sum[ i + 1 ][ j + k - 1 ] - sum[ i + 1 ][ j - 1 ];

       那么现在重合只算一次, 我们要怎么处理呢。

       若我们当前在算 dp[ i ][ j ], 那 a[ i ][ j ] ~ a[ i ][ j + k - 1 ]  都有可能被算过了, 那我们就对那些包含 (i, j) 这个点的区域都减去 a[ i ][ j ] 再取最大值。

       比如说,假设现在 k = 2, 你当前在算 dp[ 2 ][ 1 ] 那你 a[ 2 ][ 1 ] 就已经被 dp[ 1 ][ 1 ] 算过了, 那你dp[ 1 ][ 1 ] 要先减去 a[ 2 ][ 1 ];

       同理, 你 dp[ 2 ][ 1] 包含的 a[ 2 ][ 2 ] 可能被 dp[ 1 ][ 1 ] 和 dp[ 1 ][ 2 ]算过了, 那你 dp [ 1 ][ 1 ] 和 dp[ 1 ][ 2 ] 都要减去 a[ 2 ][ 2 ];

      然后再用那个转移方程求 dp[ i ][ j ]; 算完后你会往右滑动窗口, 这时, 你需要讲那些被减的重新加回来。

      你算完 dp[ 2 ][ 1 ] 后你要算 dp[ 2 ][ 2 ] 那你 a[ 2 ][ 1 ] 是不被 dp[ 2 ][ 2 ] 包含到的, 但你 dp[ 1 ][ 1 ] 已经减掉 a[ 2 ][ 1 ]了, 那现在就得重新加回来。

      同理,你 dp[ 2 ][ 2 ] 包含到了一个 新的可能已经被算过的点 dp[ 2 ][ 3 ], 那你同样要减掉, 再求最大值。

         减掉和求最大值的操作可以用线段树完成。  对应的就是 区间更新和区间求最大值。

      

    #include <bits/stdc++.h>
    #define LL long long
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF INT_MAX
    #define inf LLONG_MAX
    #define PI acos(-1)
    using namespace std;
    
    const int N = 2e4 + 5;
    
    struct note {
        int val, lz;
    }t[N << 2];
    int sum[55][N];
    int dp[55][N];
    
    void build(int rt, int l, int r) {
        if(l == r) {
            t[rt].val = 0; return ;
        }
        int mid = (l + r) >> 1;
        build(rt << 1, l, mid);
        build(rt << 1 | 1, mid + 1, r);
        t[rt].val = max(t[rt << 1].val, t[rt << 1 | 1].val);
    }
    
    void pushdown(int rt) {
        t[rt << 1].lz += t[rt].lz;
        t[rt << 1 | 1].lz += t[rt].lz;
        t[rt << 1].val += t[rt].lz;
        t[rt << 1 | 1].val += t[rt].lz;
        t[rt].lz = 0;
    }
    
    void update(int rt, int l, int r, int L, int R, int x) {
        if(L <= l && r <= R) {
            t[rt].lz += x; t[rt].val += x; return ;
        }
        if(t[rt].lz) pushdown(rt);
        int mid = (l + r) >> 1;
        if(R <= mid) update(rt << 1, l, mid, L, R, x);
        else if(L > mid) update(rt << 1 | 1, mid + 1, r, L, R, x);
        else {
            update(rt << 1, l, mid, L, R, x);
            update(rt << 1 | 1, mid + 1, r, L, R, x);
        }
        t[rt].val = max(t[rt << 1].val, t[rt << 1 | 1].val);
    }
    
    int a[55][N];
    int main() {
    
    
        int n, m, k; scanf("%d %d %d", &n, &m, &k);
        rep(i, 1, n) rep(j, 1, m) {
            scanf("%d", &a[i][j]); sum[i][j] = sum[i][j - 1] + a[i][j];
        }
        rep(i, 1, m - k + 1) {
            dp[1][i] = sum[1][i + k - 1] - sum[1][i - 1] + sum[2][i + k - 1] - sum[2][i - 1];
        }
        rep(i, 2, n) {
            mem(t, 0);
            rep(j, 1, m - k + 1) update(1, 1, m - k + 1, j, j, dp[i-1][j]);
            rep(j, 1, k) update(1, 1, m - k + 1, 1, j, -a[i][j]);
            rep(j, 1, m - k + 1) {
                dp[i][j] = t[1].val + sum[i][j + k - 1] - sum[i][j - 1] + sum[i + 1][j + k - 1] - sum[i + 1][j - 1];
    
                if(j != m - k + 1) {
                    update(1, 1, m - k + 1, max(1, j - k + 1), j, a[i][j]);
                    update(1, 1, m - k + 1, j + 1, j + k, -a[i][j + k]);
                }
            }
        }
        int ans = -1;
        rep(i, 1, m) ans = max(ans, dp[n][i]);
        printf("%d
    ", ans);
        return 0;
    }
    View Code
    一步一步,永不停息
  • 相关阅读:
    iOS与H5交互时,去掉调用方法时产生的警告
    技术支持网址:Technical support
    iPhone X 适配
    iOS11 上拉刷新后没有动画出现,直接瞬间出来没有停顿
    要不要去柬埔寨工作,很纠结,但是工资我又无法拒绝
    iOS10 CAAnimationDelegate的适配
    Swift3GCD
    Alamofire4.0 在 CocoaPods无法更新的问题
    8行代码全屏滑动
    bootstrap table 前端分页的问题
  • 原文地址:https://www.cnblogs.com/Willems/p/12330946.html
Copyright © 2011-2022 走看看