[CF1304F2]Animal Observation (hard version)

Animal Observation (hard version)

题解

可以把原题看作在一个n*m的矩阵上选取n2*k的矩形的覆盖面积的权值之和。

很容易想到dp,令dp_{i,j}为在第i行的(i,j)选做矩形的端点,不考虑下面几行情况时的最大权值和,于是转移方程式就很好想了:

dp_{i,j}=max\left\{ dp_{i-1,k}+w_{k,j}\right \}

w_{i,j}的值为从ij分别覆盖出一个长度为k的矩阵时的覆盖权值和。

我们发现对于w取值关于j改变时说做出的改变,一定是后部分与其相交的整体减去一个权值,前部分与其相交的整体加上一个权值,由于要进行区间的加减,我们可以用线段树来对其进行维护,顺便再每次维护过程中记录下最大的dp_{i-1,k}+ w_{j,k}的值。

鉴于每次更改是log_{n}的所以总复杂度是O\left(nmlog_{m} \right ),可以过去。

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 20005
typedef long long LL;
typedef pair<int,int> pii;
const LL mo=1e9+7;
const LL INF=0x7f7f7f7f;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
LL k,m,g,n,d[55][MAXN],sum[55][MAXN],ans;
LL val[MAXN<<2],lzy[MAXN<<2],dp[55][MAXN];
void pushdown(int rt){
	if(!lzy[rt])return ;
	val[rt<<1]+=lzy[rt];val[rt<<1|1]+=lzy[rt];
	lzy[rt<<1]+=lzy[rt];lzy[rt<<1|1]+=lzy[rt];
	lzy[rt]=0;
}
void build(int rt,int l,int r,int ti){
	if(l==r){val[rt]=dp[ti][l]+sum[ti+1][l+k-1]-sum[ti+1][l-1];return ;}
	LL mid=l+r>>1;
	build(rt<<1,l,mid,ti);
	build(rt<<1|1,mid+1,r,ti);
	val[rt]=max(val[rt<<1],val[rt<<1|1]);
	//printf("%d %d %d %d:%lld\n",rt,l,r,ti,val[rt]);
}
void modify(int rt,int l,int r,int al,int ar,LL aw){
	if(l>r||al>r||ar<l)return ;
	if(al<=l&&r<=ar){val[rt]+=aw,lzy[rt]+=aw;return ;}
	LL mid=l+r>>1;pushdown(rt);
	if(al<=mid)modify(rt<<1,l,mid,al,ar,aw);
	if(mid<ar)modify(rt<<1|1,mid+1,r,al,ar,aw);
	val[rt]=max(val[rt<<1],val[rt<<1|1]);
}
void add(int ti,LL pos){if(pos)modify(1,1,g,max(1LL,pos-k+1),min(g,pos),-d[ti][pos]);}
void del(int ti,LL pos){if(pos)modify(1,1,g,max(1LL,pos-k+1),min(g,pos),d[ti][pos]);}
signed main(){
	scanf("%lld %lld %lld",&n,&m,&k);g=m-k+1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%lld",&d[i][j]),sum[i][j]=sum[i][j-1]+d[i][j];
	for(int i=1;i<=n;i++){
		if(i>1)for(int j=1;j<k;j++)add(i,j);
		for(int j=1;j<=m-k+1;j++){
			int l=j,r=j+k-1;
			if(i==1)dp[i][j]=sum[i][r]-sum[i][l-1];
			else del(i,l-1),add(i,r),dp[i][j]=sum[i][r]-sum[i][l-1]+val[1];
			//printf("%d %d:%lld %lld\n",i,j,dp[i][j],val[1]);
		}
		memset(val,0,sizeof(val));
		memset(lzy,0,sizeof(lzy));
		if(i<n)build(1,1,g,i);
	}
	for(int i=1;i<=g;i++)ans=max(ans,dp[n][i]);
	printf("%lld\n",ans);
	return 0;
}

谢谢!!!

posted @ 2020-08-13 08:04  StaroForgin  阅读(15)  评论(0)    收藏  举报  来源