题意:
作者喜欢观察动物,因此他购买了两个照相机,以拍摄森林中野生动物的视频,一台摄像机的颜色是红色,一台摄像机的颜色是蓝色。
从第1天到第N天,作者将拍摄N天的视频。森林可以分为M个区域,编号从1到M。他将通过以下方式使用相机:
在每个奇数天,将红色相机带到森林中并录制两天的视频。
在每个偶数天,将蓝色相机带到森林中并录制两天的视频。
如果他在第N天使用其中一台摄像机开始录制,则该摄像机仅录制一天。
每个摄像机可以连续观察森林的K个连续的区域。
作者已经获得了有关每天在每个区域看到多少动物的信息。由于他想观察尽可能多的动物,因此他希望你找到放置两台摄像机N天的最佳方法。请注意,如果两个摄像机在同一天观察同一区域,则在该区域观察到的动物仅被计数一次。
输出一个整数,可以观察到的最大动物的数量。
题解:
开一个二维数组记录每一天每个区域的动物数量。
开一个二维数组保存每一天每个区域的前缀和,方便统计。
然后开一个二维dp数组,i表示第i天,j表示从j开始到j+k-1的区域,dp的值表示当前该区域所能拍摄的最大动物数量(前面的日子最大化操作)。
初始化dp数组,第1天dp值为区域当天的动物总和。
然后遍历第2天到第N天,每一天开始,先更新所有的dp值,即把dp值直接加上新一天区域内动物总和。
然后遍历每个区域,把与前一天拍到的重复的区域剪掉,再更新dp的值。
更新dp值这个过程需要维护一颗线段树,线段树里的mx值表示前一天能拍到动物的最大数量,tag表示子节点要加多少,存在父节点里,等查询到子节点了再更新子节点。
#include<bits/stdc++.h>
using namespace std;
const int maxn=20014;
struct node {
int l;
int r;
int mx;
int tag;
}segTree[maxn*4];
int N,M,K;
int a[60][maxn];
int sum[60][maxn];
int dp[60][maxn];
void build (int i,int l,int r,int x) {
segTree[i].l=l;
segTree[i].r=r;
segTree[i].tag=0;
if (l==r-1)
segTree[i].mx=dp[x-1][l]+sum[x][l+K-1]-sum[x][max(K-1,l-1)];
else {
int mid=(l+r)>>1;
build(i<<1,l,mid,x);
build(i<<1|1,mid,r,x);
segTree[i].mx=max(segTree[i<<1].mx,segTree[i<<1|1].mx);
}
}
void pushdown (int i) {
segTree[i<<1].mx+=segTree[i].tag;
segTree[i<<1|1].mx+=segTree[i].tag;
segTree[i<<1].tag+=segTree[i].tag;
segTree[i<<1|1].tag+=segTree[i].tag;
segTree[i].tag=0;
}
void modify (int i,int l,int r,int del) {
if (l<=segTree[i].l&&r>=segTree[i].r) {
segTree[i].mx+=del;
segTree[i].tag+=del;
return;
}
if (segTree[i].tag) pushdown(i);
int mid=(segTree[i].l+segTree[i].r)>>1;
if (l<mid) modify(i<<1,l,r,del);
if (r>mid) modify(i<<1|1,l,r,del);
segTree[i].mx=max(segTree[i<<1].mx,segTree[i<<1|1].mx);
}
void solve () {
scanf("%d%d%d",&N,&M,&K);
for (int i=1;i<=N;i++) {
sum[i][0]=0;
for (int j=1;j<=M;j++) {
scanf("%d",&a[i][j]);
sum[i][j]=sum[i][j-1]+a[i][j];
}
}
for (int j=1;j<=M-K+1;j++)
dp[1][j]=sum[1][j+K-1]-sum[1][j-1];
for (int i=2;i<=N;i++) {
build(1,1,M-K+2,i);
for (int j=1;j<=M-K+1;j++) {
modify(1,j,j+K,-a[i][j+K-1]);
dp[i][j]=segTree[1].mx+sum[i][j+K-1]-sum[i][j-1];
modify(1,max(j-K+1,1),j+1,a[i][j]);
}
}
int ans=dp[N][1];
for (int j=2;j<=M;j++)
ans=max(ans,dp[N][j]);
printf ("%d\n",ans);
}
int main () {
solve();
return 0;
}
来源:https://www.cnblogs.com/zhanglichen/p/12426231.html