1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP

题意

用摄像机观察动物,有两个摄像机,一个可以放在奇数天,一个可以放在偶数天。摄像机在同一天可以同时照到k个区域放下去可以持续两天。现在给出每一天每个区域的动物数量,问最多照到动物多少个。如果两个照相机同时照到一个动物只算一次。n<=50 k<=m<=2e4

思路

我们可以考虑只在一天的情况 那么就是一个简单的dp,状态为dp[i][j]第i天放置在区域j可以获得的最大数。那么dp[i][j]转移的时候只要取max(dp[i-1])再加上第i天放在j的收益即可。持续天数变成了两天有什么差异呢?那就是会产生覆盖的情况,如何解决这个情况呢,对于dp[i][j]来说 只有上一天的摄像机区间会和[j,j+k-1]相交的时候才要考虑这种情况,那么相交的时候,相当于上一层状态要减去和[j,j+k-1]的交集区间 例如对于dp[i-1][j+1]来说,就是要减去[j,j+k-1]和[j+1,j+k]的交集动物数也就是[j+1,j+k-1]的动物数,这里可以用滑动窗口来维护。对于长度为k的滑动窗口,当前窗口边界为j,如果j出去,表示所有[max(1,j-k+1),j]都应该加上a[i][j]那么新进来的j+k则表示所有[j+1,j+k]都应该减去a[i][j+k]因为这里采用的是区间加减的形式,所以可以用线段树进行维护,同时也可以用单调队列做法。

单调栈做法

对于dp[i-1][x]单调栈是把答案分成了三种情况讨论

1.x位于位于j-k+1的左边 即dp[i][j]由没有相交的情况转移过来直接求前缀最大值即可

2. x位于j+k-1的右边 同上 求后缀最大

3. 和[j,j+k-1]有相交的区间 这个时候就要用单调栈维护最大值了,我们可以知道的是我们维护一个k大的窗口,那么这个k大窗口里的东西都和[j,j+k-1]有相交,那么我们可以把每个入队的dp[i-1][j]减去sum[i][j..j+k-1]压入单调栈,那么对于我们求dp[i][j]而言,值qv[tail]+sum[i][q[tail]...j-1]则为减去了相交区间sum的相应dp值因为qv[tail]+sum[q[tail]..j-1]是单调递增的,即j移动的时候sum[q[tail]..j-1]要增加,就相当于对单调栈里面的每一个值都加上了了一个相同的数,单调栈里的元素的rank不会发生改变,当要状态转移的时候只需要还原值即可

这里有一个技巧对于[x1,y1] [x2,y2]如果交集是[y1,x2]即交叉的情况,如果我们要计算[x2,y2]减去[x2,y1]的值,那么我们对于区间[x1,y1]可以直接减去区间[1...y1]的值,到[x1,y1]的时候 直接加上区间[1,x2-1]则只剩下了[x2,y1]的值了,这样对于队列里的每个值都是加上区间[1,x2-1] 滑动窗口滑动的时候仅仅是x2变化即统一加的值变化了

线段树做法代码

#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
using namespace std;
typedef long long ll;
const int maxn=5e5+5;
const int mod=1e9+7;
int dp[55][maxn],a[55][maxn],sum[55][maxn];
int lazy[maxn<<2],tree[maxn<<2];
void build(int o,int l,int r){
lazy[o]=tree[o]=0;
if(l==r)return ;
int mid=l+r>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
}
void push_down(int o){
if(lazy[o]){
lazy[o<<1|1]+=lazy[o];
lazy[o<<1]+=lazy[o];
tree[o<<1|1]+=lazy[o];
tree[o<<1]+=lazy[o];
lazy[o]=0;
}
}
void push_up(int o){
tree[o]=max(tree[o<<1],tree[o<<1|1]);
}
void update(int o,int l,int r,int x,int y,int value){
if(l>=x&&r<=y){
tree[o]+=value;
lazy[o]+=value;
return ;
}
int mid=l+r>>1;
push_down(o);
if(mid>=x)update(o<<1,l,mid,x,y,value);
if(mid<y)update(o<<1|1,mid+1,r,x,y,value);
push_up(o);
}
int query(int o,int l,int r,int x,int y){
if(x<=l&&r<=y){
push_down(o);
return tree[o];
}
int mid=l+r>>1;
int ans=0;
if(mid>=x)ans=max(ans,query(o<<1,l,mid,x,y));
if(mid<y)ans=max(ans,query(o<<1|1,mid+1,r,x,y));
return ans;
}
int main(){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
sum[i][j]=sum[i][j-1]+a[i][j];
}
}
int up=m-k+1;
for(int i=1;i<=up;i++){
dp[1][i]=sum[1][i+k-1]-sum[1][i-1]+sum[2][i+k-1]-sum[2][i-1];
}
for(int i=2;i<=n;i++){
build(1,1,up);
for(int j=1;j<=up;j++)update(1,1,up,j,j,dp[i-1][j]);
for(int j=1;j<=k;j++)update(1,1,up,1,j,-a[i][j]);
for(int j=1;j<=up;j++){
dp[i][j]=query(1,1,up,1,up)+sum[i][j+k-1]-sum[i][j-1]+sum[i+1][j+k-1]-sum[i+1][j-1];
if(j<up){
update(1,1,up,max(1,j-k+1),j,a[i][j]);
update(1,1,up,j+1,j+k,-a[i][j+k]);
}
}
}
printf("%d\n",*max_element(dp[n]+1,dp[n]+up+1));
return 0;
}

单调栈

#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
using namespace std;
typedef long long ll;
const int maxn=5e5+5;
const int mod=1e9+7;
int dp[55][maxn],a[55][maxn],sum[55][maxn],q[maxn],qv[maxn];
int n,m,k;
int query(int i,int l){
return sum[i][l+k-1]-sum[i][l-1];
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
sum[i][j]=sum[i][j-1]+a[i][j];
}
}
int up=m-k+1;
for(int i=1;i<=up;i++){
dp[1][i]=query(1,i)+query(2,i);
}
for(int i=2;i<=n;i++){
int maxnum=0;
for(int j=1;j<=up;j++){
if(j-k>=1)maxnum=max(maxnum,dp[i-1][j-k]);
dp[i][j]=max(dp[i][j],maxnum+query(i,j)+query(i+1,j));
}
maxnum=0;
for(int j=up;j>=1;j--){
if(j+k<=up)maxnum=max(maxnum,dp[i-1][j+k]);
dp[i][j]=max(dp[i][j],maxnum+query(i,j)+query(i+1,j));
}
int tail=0,head=1;
for(int j=1;j<=up;j++){
int v=dp[i-1][j]-sum[i][j+k-1];
while(head<=tail&&v>=qv[tail])tail--;
qv[++tail]=v;q[tail]=j;
dp[i][j]=max(dp[i][j],qv[head]+sum[i][j-1]+query(i,j)+query(i+1,j));
while(head<=tail&&q[head]<=j-k+1)head++;
}
tail=0,head=1;
for(int j=up;j>=1;j--){
int v=dp[i-1][j]+sum[i][j-1];
while(head<=tail&&v>=qv[tail])tail--;
qv[++tail]=v;q[tail]=j;
dp[i][j]=max(dp[i][j],qv[head]-sum[i][j+k-1]+query(i,j)+query(i+1,j));
while(head<=tail&&q[head]>=j+k-1)head++;
}
}
printf("%d\n",*max_element(dp[n]+1,dp[n]+1+up));
return 0;
}

1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP的更多相关文章

  1. bzoj 1171 并查集优化顺序枚举 | 线段树套单调队列

    详见vfleaking在discuss里的题解. 收获: 当我们要顺序枚举一个序列,并且跳过某些元素,那么我们可以用并查集将要跳过的元素合并到一起,这样当一长串元素需要跳过时,可以O(1)跳过. 暴力 ...

  2. PKU 2823 Sliding Window(线段树||RMQ||单调队列)

    题目大意:原题链接(定长区间求最值) 给定长为n的数组,求出每k个数之间的最小/大值. 解法一:线段树 segtree节点存储区间的最小/大值 Query_min(int p,int l,int r, ...

  3. ACM学习历程—HDU 5289 Assignment(线段树 || RMQ || 单调队列)

    Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fro ...

  4. POJ 2823 线段树 Or 单调队列

    时限12s! 所以我用了线段树的黑暗做法,其实正解是用单调队列来做的. //By SiriusRen #include <cstdio> #include <cstring> ...

  5. 【HDU6701】Make Rounddog Happy【权值线段树+双向单调队列】

    题意:给你一个序列,求满足要求的子序列个数,其中要求为: 1.子序列的max-子序列长度len<=k 2.子序列中不出现重复的数字 题解:首先看到子序列max,很容易想到枚举最大值然后分治,这个 ...

  6. Luogu4085 [USACO17DEC]Haybale Feast (线段树,单调队列)

    \(10^18\)是要long long的. \(nlogn\)单调队列上维护\(logn\)线段树. #include <iostream> #include <cstdio> ...

  7. Codeforces 1304F2 Animal Observation (hard version) 代码(dp滑动窗口线段树区间更新优化)

    https://codeforces.com/contest/1304/problem/F2 #include<bits/stdc++.h> using namespace std; ; ...

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

    Codeforces Round #620 F2. Animal Observation (hard version) (dp + 线段树) 题目链接 题意 给定一个nm的矩阵,每行取2k的矩阵,求总 ...

  9. 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)

    D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...

随机推荐

  1. DOTNET Core MVC(二)路由初探

    搁置了几天,工作忙的一塌糊涂,今天终于抽空来继续看看MVC的知识.先来看看MVC的路由是如何处理的.以下为替代的路由: app.UseEndpoints(endpoints => { endpo ...

  2. search(0)- 企业搜索,写在前面

    计划研究一下搜索search,然后写个学习过程系列博客.开动之前先说说学习搜索的目的:不是想开发个什么搜索引擎,而是想用现成的搜索引擎在传统信息系统中引进搜索的概念和方法.对我来说,传统的管理系统le ...

  3. kali帮助

    kali help Attention 这是我N久前学习kali时自己打的东西,不保证没有纰漏啊…… 网址 kali:https://www.herojd.com/forum.php?mod=view ...

  4. Jenkins集成jacoco收集单元测试覆盖率

    Jenkins集成jacoco收集单元测试覆盖率 2020-02-28 目录 0 整体思路1 Jenkins创建JacocoIntegrateTestDemo项目2 配置源码管理3 配置Build4 ...

  5. 《ADCrowdNet》密集人群检测论文笔记

    背景 为了解决高密度的计数问题.(PS:就是attention机制的应用) 网络 整体网络结构图 attention部分的网络AMG 密度图预测网络 DConv代表可变形卷积,下图是常规卷积(左)与可 ...

  6. 使用HSSFWorkbook导出、操作excel

    原文地址:https://www.jianshu.com/p/dd1e4f28757b 在实际开发中我们经常需要导入数据,统计数据,并且将统计好的数据导出excel,今天分享一个导出学生信息的方法. ...

  7. luogu P3369 【模板】普通平衡树

    ————————————————版权声明:本文为CSDN博主「ModestCoder_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明.原文链接:https:// ...

  8. CentOS7安装postgreSQL11

    1.添加PostgreSQL Yum存储库 sudo yum install https://download.postgresql.org/pub/repos/yum/11/redhat/rhel- ...

  9. Tomcat8.5安装与配置的坑

    本文只是单纯记录一下tomcat配置的坑! 1.下载官网:https://tomcat.apache.org/下载后解压到根目录,盘符任意.但必须有jdk,本人用的是jdk1.8 2.配置环境变量在c ...

  10. clientHeight offsetTop scrollTop