「Wdoi-4」Luogu P7872 题解

Description

传送门

Solution

为方便叙述,令扫地的古明地觉为 A,走路的古明地恋为 B。

首先,考虑当 A 和 B 的路线都固定时,如何找出最优解。

分成两类讨论:

  • A 的终点与 B 的终点相同(即 x s = x k , y s = y k x_s=x_k,y_s=y_k xs=xk,ys=yk)。此时两路线的最长公共后缀为一段非空的区间,在图中用黑色表示;剩余部分中,由 A 走的部分为绿色,由 B 走的部分为红色。不难发现,所有仅被绿色经过的点 ( i , j ) (i,j) (i,j) 的贡献均为 a i , j a_{i,j} ai,j,被染为黑色的点的贡献也均为 a i , j a_{i,j} ai,j;所有同时被红和绿经过的点 ( i , j ) (i,j) (i,j) 的贡献均为 max ⁡ ( a i , j , 0 ) \max(a_{i,j},0) max(ai,j,0),所有仅被红色经过的点 ( i , j ) (i,j) (i,j) 的贡献也均为 max ⁡ ( a i , j , 0 ) \max(a_{i,j},0) max(ai,j,0)。无色点贡献显然都是 0 0 0
    在这里插入图片描述
  • A 的终点与 B 的终点不同。此时两路线的最长不相交后缀为一段非空的区间,在图中用黑色表示;剩余部分中,由 A 走的部分为绿色,由 B 走的部分为红色。不难发现,所有仅被绿色经过的点 ( i , j ) (i,j) (i,j) 的贡献均为 a i , j a_{i,j} ai,j,被染为黑色且由 A 经过点的贡献也均为 a i , j a_{i,j} ai,j;所有同时被红和绿经过的点 ( i , j ) (i,j) (i,j) 的贡献均为 max ⁡ ( a i , j , 0 ) \max(a_{i,j},0) max(ai,j,0),所有仅被红色经过的点 ( i , j ) (i,j) (i,j) 的贡献也均为 max ⁡ ( a i , j , 0 ) \max(a_{i,j},0) max(ai,j,0)。其他点的贡献都是 0 0 0
    在这里插入图片描述

于是我们就可以愉快地 dp \text{dp} dp 了。

f i , j , k f_{i,j,k} fi,j,k 表示,当 A 和 B 同时从 ( 1 , 1 ) (1,1) (1,1) 出发且 B 走到 ( i , j ) (i,j) (i,j),A 走到 ( k , i + j − k ) (k,i+j-k) (k,i+jk) 时(所有坐标必须全部合法),所有经过的点的最大贡献和。注意,这里我们不考虑任何黑色路线的贡献,只考虑红绿两部分。

g i , j g_{i,j} gi,j 表示,从 ( i , j ) (i,j) (i,j) 出发到达 ( x k , y k ) (x_k,y_k) (xk,yk) 的最大点权和。这是黑色贡献的体现。

g g g 的转移十分容易,那么 f f f 该如何转移呢?首先, f i , j , k f_{i,j,k} fi,j,k 可以由 4 4 4 个不同的前驱得到,分别为 f i , j − 1 , k , f i − 1 , j , k , f i , j − 1 , k − 1 , f i − 1 , j , k − 1 f_{i,j-1,k},f_{i-1,j,k},f_{i,j-1,k-1},f_{i-1,j,k-1} fi,j1,k,fi1,j,k,fi,j1,k1,fi1,j,k1。其次,我们还需要在原来的总贡献上加上当前新扩展出的 ( i , j ) ( k , i + j − k ) (i,j)(k,i+j-k) (i,j)(k,i+jk) 的贡献——若 i ≠ k i \neq k i=k 则两点不重合,应加上 a i , j + max ⁡ ( a k , i + j − k , 0 ) a_{i,j}+\max(a_{k,i+j-k},0) ai,j+max(ak,i+jk,0);否则两点重合,应加上 max ⁡ ( a i , j , 0 ) \max(a_{i,j},0) max(ai,j,0)

至于如何计算答案,根据上面的两类讨论很容易得到:

  • a n s : = max ⁡ ( a n s , f i , j − 1 , i − 1 + g i , j ) ans:=\max(ans,f_{i,j-1,i-1}+g_{i,j}) ans:=max(ans,fi,j1,i1+gi,j)(第一类)
  • a n s : = max ⁡ ( a n s , f i − 1 , j , i + g i , j ) ans:=\max(ans,f_{i-1,j,i}+g_{i,j}) ans:=max(ans,fi1,j,i+gi,j)(第一类)
  • a n s : = max ⁡ ( a n s , f i , j , i + g i + 1 , j ) ans:=\max(ans,f_{i,j,i}+g_{i+1,j}) ans:=max(ans,fi,j,i+gi+1,j)(第二类)
  • a n s : = max ⁡ ( a n s , f i , j , i + g i , j + 1 ) ans:=\max(ans,f_{i,j,i}+g_{i,j+1}) ans:=max(ans,fi,j,i+gi,j+1)(第二类)

一定注意还有 a n s : = max ⁡ ( a n s , g 1 , 1 ) ans:=\max(ans,g_{1,1}) ans:=max(ans,g1,1),这属于第二类情况。

总时间复杂度 O ( n 3 ) O(n^3) O(n3),可以通过本题。

Code

#include <bits/stdc++.h>
#define int long long
#define inf 200000000000000007
using namespace std;
const int maxl=305;

int read(){
    
    
	int s=0,w=1;char ch=getchar();
	while (ch<'0'||ch>'9'){
    
    if (ch=='-')  w=-w;ch=getchar();}
	while (ch>='0'&&ch<='9'){
    
    s=(s<<1)+(s<<3)+(ch^'0');ch=getchar();}
	return s*w;
}
int n,m,sx,sy,tx,ty,ans=-inf;
int a[maxl][maxl],f[maxl][maxl][maxl],g[maxl][maxl];
bool chk(int x,int y,int xx,int yy){
    
    return (x<=xx&&y<=yy&&1<=x&&1<=y);}

signed main(){
    
    
	n=read(),m=read();
	for (int i=1;i<=n;i++){
    
    
		for (int j=1;j<=m;j++)  a[i][j]=read();
	}
	for (int i=0;i<=n+1;i++){
    
    
		for (int j=0;j<=m+1;j++){
    
    
			g[i][j]=-inf;
			for (int k=0;k<=n+1;k++)  f[i][j][k]=-inf;
		}
	}
	tx=read(),ty=read(),sx=read(),sy=read();
	
	g[sx][sy]=a[sx][sy];
	for (int i=sx;i>=1;i--){
    
    
		for (int j=sy;j>=1;j--){
    
    
			if (i)  g[i-1][j]=max(g[i-1][j],g[i][j]+a[i-1][j]);
			if (j)  g[i][j-1]=max(g[i][j-1],g[i][j]+a[i][j-1]);
		}
	}
	f[1][1][1]=max(a[1][1],0ll),ans=g[1][1];
	for (int i=1;i<=sx;i++){
    
    
		for (int j=1;j<=sy;j++){
    
    
			for (int k=max(1ll,i+j-ty);k<=min(i+j-1,tx);k++){
    
    
				int w=i+j-k,delta=((i==k)?(max(a[i][j],0ll)):(a[i][j]+max(a[k][w],0ll)));
				if (i!=1||j!=1||k!=1)  f[i][j][k]=max(max(f[i-1][j][k],f[i-1][j][k-1]),max(f[i][j-1][k],f[i][j-1][k-1]))+delta;
				if (chk(i+1,j,sx,sy)&&chk(i,j+1,tx,ty))  ans=max(ans,f[i][j][i]+g[i+1][j]);
				if (chk(i,j+1,sx,sy)&&chk(i+1,j,tx,ty))  ans=max(ans,f[i][j][i]+g[i][j+1]);
				if (sx==tx&&sy==ty&&chk(i,j,sx,sy)&&chk(i,j,tx,ty))  ans=max(ans,max(f[i-1][j][i],f[i][j-1][i-1])+g[i][j]);
			}
		}
	}
	cout<<ans<<endl;
	return 0; 
}

猜你喜欢

转载自blog.csdn.net/Cherrt/article/details/121621227