NC17070 矩阵(前缀和+单调队列)

最大子矩阵和问题,一般都是用前缀和先计算行,然后枚举行,在列方向做单调队列

这样的复杂度是N^3,对于几百的数据足够了

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<map>
#include<string>
using namespace std;
typedef long long ll;
const int N=2e5+5;
const int mod=19260817;
ll g[505];
ll a[505][505];
ll zero[505][505];
int q[N];
ll tmp[505];
int main(){
    int r,c;
    int x,y,z;
    cin>>r>>c>>x>>y>>z;
    int i,j;
    for(i=1;i<=r;i++){
        for(j=1;j<=c;j++){
            scanf("%lld",&a[i][j]);
            if(a[i][j]==0){
                zero[i][j]=zero[i-1][j]+1;
            }
            else{
                zero[i][j]=zero[i-1][j];
            }
            a[i][j]+=a[i-1][j];
        }
    }
    ll ans=0;
    int k;
    for(i=1;i<=r;i++){
        for(j=i;j<i+x&&j<=r;j++){
            int hh=0,tt=0;
            q[0]=0;
            memset(g,0,sizeof g);
            memset(tmp,0,sizeof tmp);
            for(k=1;k<=c;k++){
                g[k]=a[j][k]-a[i-1][k]+g[k-1];
                tmp[k]=zero[j][k]-zero[i-1][k]+tmp[k-1];
                while(hh<=tt&&(tmp[k]-tmp[q[hh]]>z||k-q[hh]>y))
                    hh++;
                if(hh<=tt)
                    ans=max(ans,g[k]-g[q[hh]]);
                while(hh<=tt&&g[q[tt]]>=g[k])
                    tt--;
                q[++tt]=k;

            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/ctyakwf/p/12685830.html

时间: 2024-08-30 07:34:02

NC17070 矩阵(前缀和+单调队列)的相关文章

AcWing:135. 最大子序和(前缀和 + 单调队列)

输入一个长度为n的整数序列,从中找出一段长度不超过m的连续子序列,使得子序列中所有数的和最大. 输入格式 第一行输入两个整数n,m. 第二行输入n个数,代表长度为n的整数序列. 同一行数之间用空格隔开. 输出格式 输出一个整数,代表该序列的最大子序和. 数据范围 1≤n,m≤3000001≤n,m≤300000 输入样例: 6 4 1 -3 5 1 -2 3 输出样例: 7 算法:前缀和 + 单调队列 注意:单调队列需要使用双端队列deque,因为其中需要头部弹出以及尾部弹出. #include

tyvj 1305 —— 长度不超过m的最大连续和 【前缀和+单调队列】

题目:http://www.tyvj.cn/p/1305 定义: sum[i]=a[1]+a[2]+...+a[i] 即,sum[i]为序列a的前缀和 dp[i] = sum[i] - min(sum[j]) (i-j<m) 即,dp[i]为以i结尾的满足长度不大于m的最大连续和 则: 答案为 max(dp[i]) (1≤i≤n) #include <cstdio> #include <iostream> using namespace std; int sum[300005

bzoj3316 JC loves Mkk 二分答案 单调队列

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3316 题意:给出一个环,求出长度在$L~R$之间任意偶数的一个序列,使得这个序列的平均值最大. 看到分数就知道这题不可做-- 好啦言归正传--这道题应该怎么做呢--直接上$PoPoQQQ$大爷的语录: 看到环果断倍增 看到平均值最大果断二分答案 看到长度[L,R]果断单调队列 没错就是这样--平均值这个东西其实就是要这么瞎搞--二分答案,然后给每个元素"咔嚓"一下去掉二分的值,之后

Gym - 101234J Zero Game (单调队列优化dp)

题意:有一个长度为n的01序列,你可以移动k次,每次将一个数移到任意一个位置,求经过操作后区间连续最大的连续0的个数. “移动”操作看似情况很复杂,不好讨论,但其实无非就两种情况: 一.移动的是1:显然最优的策略是将1移动到最边上(相当于“移走”),目的是将两段连续的0合并. 二.移动的是0:最优策略是将小堆中的0移动到大堆里,目的是增加大堆中0的个数. 这样一来,情况就简单多了,问题转化成了求“将一段连续区间中的0合并,然后剩下的操作次数用于把其他地方的0引进来”的最优解,即求$min(max

BZOJ_1096_[ZJOI2007]_仓库建设_(斜率优化动态规划+单调队列+特殊的前缀和技巧)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1096 有\(n\)个工厂,给出第\(i\)个工厂的到1号工厂的距离\(x[i]\),货物数量\(p[i]\),建设仓库所需花费\(c[i]\). 现在要把所有货物都装入仓库,第\(i\)号工厂的货物可以选择在\(i\)建仓库并存入,或者移动到\(k\)号仓库\((i<k<=n)\).移动的花费为数量与距离的乘积. 分析 我们来想一想dp方程. 用\(dp[i]\)表示前\(i\)个工厂,且

【BZOJ4385】[POI2015]Wilcze do?y【单调队列】【前缀和】【Two Pointers】

[题目链接] 题解: 如果区间[j, i]固定,那么一定是将权值最大的一段变为0. 用单调队列维护一段区间内权值最大的子段下标(这里记录右端点下标,设为x),枚举右端点i,用尺取法计算出j. 一段区间[j, i]合法的条件是sum[i] - sum[j - 1] - (sum[x] - sum[x - d]) <= p. 复杂度: 时间复杂度:因为每个点最多遍历2次,复杂度为O(n). 空间复杂度:O(n) RE: 更新j的时候忘写h <= t了.如果写对拍的话应该可以拍出来. GET: 如果

单调队列&amp;单调栈归纳

单调队列 求长度为M的区间内的最大(小)值 单调队列的基本操作,也就是经典的滑动窗口问题. 求长度为M的区间内最大值和最小值的最大差值 两个单调队列,求出长度为M的区间最大最小值的数组,分别求最大最小值. 求边长为a的正方形内最大值和最小值的最大差值([HAOI2007]理想的正方形) 一个大体的思路是先分别求出以i,j为左上端点的边长为a的矩形中的最大值和最小值.那么该怎么做?,先用单调队列求出一个点右边a个单位的最大值,形成一个新矩阵,再求出新矩阵下边a个单位的最大值.然后最小值再求一边,最

codevs3327选择数字(单调队列优化)

3327 选择数字 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 给定一行n个非负整数a[1]..a[n].现在你可以选择其中若干个数,但不能有超过k个连续的数字被选择.你的任务是使得选出的数字的和最大. 输入描述 Input Description 第一行两个整数n,k 以下n行,每行一个整数表示a[i]. 输出描述 Output Description 输出一个值表示答案. 样例输入 Sample Input 5 2

UVA Live Achrive 4327 Parade (单调队列,dp)

容易想到dp[i][j]表示在第i行j个路口的开始走最大高兴值. 每次可以向左走,或者向右边走,然后向北走.(或者直接往北) 向左走到,状态转移为dp[i][j] = dp[i][k] + happy[i][k][j](为了方便处理,i从1开始编号,0行dp值存0) 处理出前缀和,happy[i][k][j]表示为sum[i][j] - sum[i][k] 向左走应该取max(dp[i][k]-sum[i][k]) k应该满足time[i][k][j] <= k 随着j的变化k的范围是一个滑动窗