Codeforces Round #620 Div2F Animal Observation(前缀和+动态规划+线段树维护)
题意:
作者喜欢观察动物,因此他购买了两个照相机,以拍摄森林中野生动物的视频,一台摄像机的颜色是红色,一台摄像机的颜色是蓝色。
从第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; }