1. 程式人生 > >5873. 小p的屬性

5873. 小p的屬性

題目大意:

在這裡插入圖片描述 思路:

把問題轉化一下,就是在一個二維的平面上,有些點有權值,你每次都可以向右或者向上走,經過一個點後得到他的權值,並且每走一步都會再次加上他的權值,問你走k步的最大權值是多少,k=10e9。 我們發現他每次走都會走到某個點上,這樣答案才會更優,所以我們把所有點的橫座標縱座標拿出來離散,然後插入點值,這樣就可以不用列舉座標了。先預處理字首和!

程式:

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 2005
#define LL long long
using namespace std;
struct data{LL x,y,z;}x[N];
LL sum[N][N],f[N][N],b[N];
LL n,m,size,cnt;
int main(){
	freopen("growth.in","r",stdin);
	freopen("growth.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	for (int i=1;i<=n;i++) {
		scanf("%lld%lld%lld",&x[i].x,&x[i].y,&x[i].z);
	} 
	for (int i=1;i<=n;i++) b[++cnt]=x[i].x,b[++cnt]=x[i].y;
	sort(b+1,b+cnt+1);
	size=unique(b+1,b+cnt+1)-b-1;
	for (int i=1;i<=n;i++){
		x[i].x=lower_bound(b+1,b+size+1,x[i].x)-b;
		x[i].y=lower_bound(b+1,b+size+1,x[i].y)-b;
		sum[x[i].x][x[i].y]+=x[i].z;
	}
	for (int i=1;i<=size;i++)
	 for (int j=1;j<=size;j++){
	 	sum[i][j]=sum[i-1][j]+sum[i][j-1]+sum[i][j]-sum[i-1][j-1];
	 }
	for (int i=1;i<=size;i++)
	 for (int j=1;j<=size;j++){
	 	if (i==1&&j==1) continue;
	 	f[i][j]=max(f[i-1][j]+sum[i-1][j]*(b[i]-b[i-1]-1),f[i][j-1]+sum[i][j-1]*(b[j]-b[j-1]-1))+sum[i][j];
	 }
	 LL ans=0;
	 for (int i=1;i<=size;i++)
	  for (int j=1;j<=size;j++)
	   if (b[i]+b[j]<=m){
	   	ans=max(ans,f[i][j]+sum[i][j]*(m-b[i]-b[j]));
	   }
	printf("%lld\n",ans);
}