2018CCPC网络赛T10题解

11 篇文章 0 订阅
9 篇文章 0 订阅

题目

YJJ's Salesman

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1299    Accepted Submission(s): 455

Problem Description

YJJ is a salesman who has traveled through western country. YJJ is always on journey. Either is he at the destination, or on the way to destination.
One day, he is going to travel from city A to southeastern city B. Let us assume that A is (0,0) on the rectangle map and B (109,109). YJJ is so busy so he never turn back or go twice the same way, he will only move to east, south or southeast, which means, if YJJ is at (x,y) now (0≤x≤109,0≤y≤109), he will only forward to (x+1,y), (x,y+1) or (x+1,y+1).
On the rectangle map from (0,0) to (109,109), there are several villages scattering on the map. Villagers will do business deals with salesmen from northwestern, but not northern or western. In mathematical language, this means when there is a village k on (xk,yk) (1≤xk≤109,1≤yk≤109), only the one who was from (xk−1,yk−1) to (xk,yk) will be able to earn vk dollars.(YJJ may get different number of dollars from different village.)
YJJ has no time to plan the path, can you help him to find maximum of dollars YJJ can get.

Input

The first line of the input contains an integer T (1≤T≤10),which is the number of test cases.

In each case, the first line of the input contains an integer N (1≤N≤105).The following N lines, the k-th line contains 3 integers, xk,yk,vk (0≤vk≤103), which indicate that there is a village on (xk,yk) and he can get vk dollars in that village.
The positions of each village is distinct.

Output

The maximum of dollars YJJ can get.

Sample Input

1

3

1 1 1

1 2 2

3 3 1

Sample Output

3

题意

存在一个1e9*1e9的地图,一个销售员从(0,0)点要走到(1e9,1e9)的位置。设他现在所在的位置为(x,y)则他下一步走到(x+1,y),(x,y+1)或(x+1, y+1)。给出n个坐标数据,表示在(xi, yi)处且当销售员是由(xi-1, yi-1)处到达该处可以赚取vi美元。求销售员走一遍地图最高可赚到多少美元。

题解

题目给的是1e9*1e9的地图(明显数据太大),但由于仅给出n的数据(n<=1e5),因此我们需对其离散化后开辟一个1e5*1e5的地图,之后DP(转移方程dp[i][j] = max(dp[i][j], dp[i-1][x](1<=x<j)+v[i][j]))跑一遍发现时间复杂度明显超时了(其实1e5*1e5的空间也超了)。这时联想到01背包中的滚动数组,实际上我们仅需开辟一维大小为1e5的数组即可,状态方程为dp[j] = max(dp[j], dp[x]+v[i][j])。

dp[x]是区间(1,j-1)的最大值。区间最大值查询我们可以使用线段树查询,查询一次时间复杂度大概是O(logn)。所以整个算法的时间复杂度大概是O(nlogn),这样时间,空间复杂度满足条件成功AC。

唉,菜鸡比赛时还是不会,过后补题。

AC代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MaxN = 1e5+10;
struct Data{
    int x, y, val;
};
Data data[MaxN];
bool cmp(const Data &a, const Data &b){
	if(a.x == b.x){
		return a.y > b.y;
	}
	return a.x < b.x;
}
bool Cmp(const Data &a, const Data &b){
    return a.y < b.y;
}
struct node{
    int l, r, val;
};
node Tree[MaxN*4];
int Hash[MaxN];
void reset(int n){
    Hash[1] = 1;
    sort(data+1, data+n+1, Cmp);
    for(int i = 2; i <= n; i++){
        if(data[i].y != data[i-1].y) Hash[i] = Hash[i-1]+1;
        else Hash[i] = Hash[i-1];
    }
    for(int i = 1; i <= n; i++){
        data[i].y = Hash[i];
    }
    sort(data+1, data+n+1, cmp);
}
void build(int idx, int L, int R){
    Tree[idx].l = L;
    Tree[idx].r = R;
    if(L == R){
        Tree[idx].val = 0;
        return;
    }
    int mid = (L+R)>>1;
    build(idx*2, L, mid);
    build(idx*2+1, mid+1, R); 
    Tree[idx].val = max(Tree[idx*2].val, Tree[idx*2+1].val);
}
int quary(int idx, int L, int R){
    if(L <= Tree[idx].l && Tree[idx].r <= R){
        return Tree[idx].val;
    }
    int mid = (Tree[idx].l + Tree[idx].r)>>1;
    if(R <= mid){
        return quary(idx*2, L, R);
    }
    else if(mid < L){
        return quary(idx*2+1, L, R);
    }
    else{
        return max(quary(idx*2, L, mid), quary(idx*2+1, mid+1, R));
    }
}
void updata(int idx, int L, int R, int val){
    if(L <= Tree[idx].l && Tree[idx].r <= R){
        Tree[idx].val = max(Tree[idx].val, val);
    }
    else if(R < Tree[idx].l || Tree[idx].r < L){
        return;
    }
    else{
        updata(idx*2, L, R, val); 
        updata(idx*2+1, L, R, val);
        Tree[idx].val = max(Tree[idx*2].val, Tree[idx*2+1].val);
    }
}
int main(){
    int T, n;
    scanf("%d", &T);
    while(T--){
        scanf("%d", &n);
        data[0].x = 0;
        data[0].y = 0;
        data[0].val = 0;
        for(int i = 1; i <= n; i++){
            scanf("%d%d%d", &data[i].x, &data[i].y, &data[i].val);
        }
        reset(n);
        build(1, 1, Hash[n]);
        int sum = 0;
        for(int i = 1; i <= n; i++){
            int temp = data[i].val;
            if(data[i].y!=1)
                temp += quary(1, 1, data[i].y-1);
            updata(1, data[i].y,data[i].y, temp);
            sum = max(sum, temp);
        }
        printf("%d\n", sum);
    } 
    return 0;
} 
/*
5
1 3 5
1 8 1
7 5 1
7 7 3
2 3 5
*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值