P4056 [JSOI2009] 火星藏宝图题解

题目背景

JSOI2009第三轮二试

题目描述

在火星游玩多日,jyy 偶然地发现了一张藏宝图。根据藏宝图上说法,宝藏被埋藏在一个巨大的湖里的 N 个岛上 (2≤N≤2×105)。为了方便描述,地图把整个湖划分成 M 行 M 列 (1≤M≤1000),共 M×M 个小块,并把所有岛按照 1...N 编了号。第 i 个岛位于第 Xi​ 行 Yi​ 列 (设其坐标为 (Xi​,Yi​)的格子 ( Xi​,Yi​ 均为整数,并且满足 1<=Xi​,Yi​<=M ),岛上藏有价值财富 Vi​(1≤Vi​≤10,000)。湖的左上角 (1,1) 和右下角 (M,M) 都有岛,有桥将它们与陆地相连。

jyy 没费多大劲,就找到了那个湖,同时哭笑不得地发现,所谓的财富,是各个岛上出产的珍稀水果。jyy 在左上角的岛的岸边找到了一条小木船,他可以划船到其他岛上去。划船是要消耗体力的,具体地说,等于两岛 Euclidean 距离的平方(即,从 (X1​,Y1​) 划船到 (X2​,Y2​) 所耗费的体力为 (X1​−X2​)2+(Y1​−Y2​)2 个单位)。jyy 可以吃水果来恢复体力,吃掉 1 单位价值的水果能恢复 1 单位体力。

现在 jyy 打算从 (1,1) 旅行到 (M,M),沿途收集珍稀水果。按藏宝图上的提示,jyy 离开一个岛后,就只能去该岛右下方的区域(正下和正右方向也是允许的),否则会遭遇水怪。jyy 可以在旅行途中饿一段时间,即体力为负。但抵达终点后,只要身边有足够多的水果,他就会通过吃水果将体力恢复到旅行前的水平。

jyy想知道,经过一次旅行,他最多能得到多少收益,即 jyy 收集到的水果总价值- jyy 在旅途中花的总体力 。(如果吃完所有水果他还饿着,收益就是负数,具体的例子见样例)

输入格式

第 1 行:两个整数 N,M。第 2...N+1 行:每行 3 个整数,第 i+1 行的 3 个整数分别为 Xi​,Yi​,Vi​。每个岛的坐标不同。保证存在坐标 (1,1) 和 (M,M) 的岛。

输出格式

第 1 行:输出一个整数,表示最大收益。

输入输出样例

输入 #1复制

4  10 
1  1  20 
10 10 10 
3  5  60 
5  3  30

输出 #1复制

-4

说明/提示

样例解释

20+60+10−((3−1)2+(5−1)2)−((10−3)2+(10−5)2)=−4

数据范围

对 20% 的数据 M≤200,且 N≤2×103。

对 50% 的数据 M≤200,且 N≤2×104。

对 100% 的数据 M≤1000,且 N≤2×105。

思路

首先,排序,写出朴素DP。

代码

#include<bits/stdc++.h>
using namespace std;
long long n,m,f[200005];
struct one{
    long long x,y,v;
}a[200005];
bool cmp(one a1,one b1){
    if(a1.x!=b1.x){
        return a1.x<b1.x;
    }
    else{
        return a1.y<b1.y;
    }
}
int main(){
	cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i].x>>a[i].y>>a[i].v;
    }
    sort(a+1,a+n+1,cmp);
    memset(f,-62,sizeof(f));
    f[1]=a[1].v;
    for(int i=2;i<=n;i++){
        for(int j=1;j<=i-1;j++){
            if(a[j].x<=a[i].x&&a[j].y<=a[i].y){
                f[i]=max(f[i],f[j]-(a[i].x-a[j].x)*(a[i].x-a[j].x)-(a[i].y-a[j].y)*(a[i].y-a[j].y)+a[i].v);
            }
        }
    }
    cout<<f[n]<<endl;
	return 0;
}

然后,再进行优化:

代码见下

#include<bits/stdc++.h>
using namespace std;
long long n,m,f[200005];
struct one{
    long long x,y,v;
}a[200005];
bool cmp(one a1,one b1){
    if(a1.x!=b1.x){
        return a1.x<b1.x;
    }
    else{
        return a1.y<b1.y;
    }
}
int main(){
	cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i].x>>a[i].y>>a[i].v;
    }
    sort(a+1,a+n+1,cmp);
    memset(f,-62,sizeof(f));
    f[1]=a[1].v;
    for(int i=2;i<=n;i++){
        if(n<=20004){
            for(int j=1;j<=i-1;j++){
                if(a[j].x<=a[i].x&&a[j].y<=a[i].y){
                    f[i]=max(f[i],f[j]-(a[i].x-a[j].x)*(a[i].x-a[j].x)-(a[i].y-a[j].y)*(a[i].y-a[j].y)+a[i].v);
                }
            }            
        }
        else{
            for(int j=max(1,i-1-3000);j<=i-1;j++){
                if(a[j].x<=a[i].x&&a[j].y<=a[i].y){
                    f[i]=max(f[i],f[j]-(a[i].x-a[j].x)*(a[i].x-a[j].x)-(a[i].y-a[j].y)*(a[i].y-a[j].y)+a[i].v);
                }
            }            
        }
    }
    cout<<f[n]<<endl;
	return 0;
}

posted @ 2025-10-24 15:55  bz02_2023f2  阅读(1)  评论(0)    收藏  举报  来源