zoukankan      html  css  js  c++  java
  • HDU 6447

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6447

    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

    Source
    2018中国大学生程序设计竞赛 - 网络选拔赛

    题意:

    从 $(0,0)$ 往 $(10^9,10^9)$ 走,每次只能从 $left( {x,y} ight)$ 走到 $left( {x + 1,y} ight)$ 或者 $left( {x,y + 1} ight)$ 或者 $left( {x + 1,y + 1} ight)$,不能折返,不能走重复的路,

    在地图上分布着一些村庄,给出村庄的坐标 $left( {x,y} ight)$ 和 $v$ 值,当且仅当你从 $left( {x - 1,y - 1} ight)$ 走到村庄时,你才可以获得 $v$,求最大能获得多少 $v$。

    题解:

    显然,假设我走到了某一个村庄 $left( {x_0,y_0} ight)$,那么只有在 $x ge x_0 + 1$ 且 $y ge y_0 + 1$ 范围内的村庄,能使得我的 $v$ 值进一步增加,

    换句话说,我走到了某一个村庄 $left( {x_0,y_0} ight)$,我上一个走到的“有意义的”村庄必然是在 $x le x_0 - 1$ 且 $y le y_0 - 1$ 的范围内的,

    那么我就要在 $x le x_0 - 1$ 且 $y le y_0 - 1$ 的范围内找到某个村庄,我走到该村庄时,我获得的 $v$ 值时最大的,

    故,我们假设 $dpleft[ i ight]$ 为走到村庄 $i$ 时能获得的最大的 $v$,则状态转移方程为:

    $dpleft[ i ight] = max left( {dpleft[ j ight] + vleft[ i ight]} ight)$,其中村庄 $j$ 的坐标 $left( {x,y} ight)$ 满足 $x le x_0 - 1$ 且 $y le y_0 - 1$

     

    那么,简单地说,对于每个村庄,要能 $Oleft( {log n} ight)$ 获得某区域内的最大值,同时也要能 $Oleft( {log n} ight)$ 的某区域内的最大值,自然而然想到树状数组……

    我们离散化纵坐标,并且从小到大枚举横坐标,用树状数组维护纵坐标为 $left[ 1,y ight]$ 区域内最大的dp[i],

    1、计算到某个横坐标值上某一村庄 $dpleft[ i ight]$,假设其纵坐标为 $y$,查询 $left[ 1,y - 1 ight]$ 区域内最大值;

    2、每次计算完某个横坐标值的一竖条上的所有村庄的 $dpleft[ i ight]$,将这一竖条上所有的 $dpleft[ i ight]$ 全部拿去更新树状数组。

     

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=1e5+10;
    
    struct Node{
        int x,y,v;
    }node[maxn];
    bool cmp(Node a,Node b)
    {
        if(a.x==b.x) return a.y<b.y;
        else return a.x<b.x;
    }
    
    int n;
    int dp[maxn];
    vector<int> X[maxn];
    
    vector<int> Y;
    inline getid(int y){return lower_bound(Y.begin(),Y.end(),y)-Y.begin()+1;}
    inline getval(int id){return Y.at(id-1);}
    
    struct _BIT
    {
        int N,C[maxn];
        int lowbit(int x){return x&(-x);}
        void init(int n)//初始化共有n个点
        {
            N=n;
            for(int i=1;i<=N;i++) C[i]=0;
        }
        void update(int pos,int val)
        {
            while(pos<=N)
            {
                C[pos]=max(C[pos],val);
                pos+=lowbit(pos);
            }
        }
        int askmax(int pos)
        {
            int ret=0;
            while(pos>0)
            {
                ret=max(ret,C[pos]);
                pos-=lowbit(pos);
            }
            return ret;
        }
    }BIT;
    
    int main()
    {
        int T;
        cin>>T;
        while(T--)
        {
            cin>>n;
            Y.clear();
            for(int i=0;i<n;i++)
            {
                scanf("%d%d%d",&node[i].x,&node[i].y,&node[i].v);
                if(node[i].x==0 || node[i].y==0) node[i].v=0;
                Y.push_back(node[i].y);
            }
    
            sort(Y.begin(),Y.end());
            Y.erase(unique(Y.begin(),Y.end()),Y.end());
    
            sort(node,node+n,cmp);
    
            int tot=0;
            for(int i=0;i<n;i++)
            {
                node[i].y = getid(node[i].y);
                if(i==0 || node[i].x>node[i-1].x)
                {
                    tot++;
                    X[tot].clear();
                }
                X[tot].push_back(i);
            }
    
            BIT.init(n);
            int ans=0;
            for(int i=1;i<=tot;i++)
            {
                int now;
                for(int j=0;j<X[i].size();j++)
                {
                    now=X[i][j];
                    dp[now]=BIT.askmax(node[now].y-1)+node[now].v;
                    ans=max(ans,dp[now]);
                }
                for(int j=0;j<X[i].size();j++)
                {
                    now=X[i][j];
                    BIT.update(node[now].y,dp[now]);
                }
            }
    
            cout<<ans<<endl;
        }
    }

    附一个bin神的代码

    #include <bits/stdc++.h>
    using namespace std;
    
    struct Node {
        int x, y, v;
        void input() {
            scanf("%d%d%d", &x ,&y, &v);
        }
    }node[100010];
    bool cmp(Node a, Node b) {
        return a.x < b.x;
    }
    
    int a[100010];
    int tot;
    
    int c[100010];
    int lowbit(int x) {
        return x&(-x);
    }
    
    void update(int i, int val) {
        while (i <= tot) {
            c[i] = max(c[i], val);
            i += lowbit(i);
        }
    }
    int query(int i) {
        int res = 0;
        while (i > 0) {
            res = max(res, c[i]);
            i -= lowbit(i);
        }
        return res;
    }
    
    int dp[100010];
    
    
    int main() {
        int T;
        int n;
        scanf("%d", &T);
        while (T--) {
            scanf("%d", &n);
            for (int i = 0; i < n; i++)
                node[i].input();
            tot = 0;
            for (int i = 0; i < n; i++) {
                a[tot++] = node[i].y;
            }
            sort(a, a+tot);
            tot = unique(a, a+tot) - a;
            for (int i = 0; i < n; i++) {
                node[i].y = lower_bound(a, a+tot, node[i].y) - a + 1;
            }
            sort(node, node+n, cmp);
            for (int i = 0; i < n; i++) dp[i] = node[i].v;
            for (int i = 1; i <= tot; i++) c[i] = 0;
            int pos = 0;
            int ans = 0;
            for (int i = 0; i < n; i++) {
                while (pos < i && node[pos].x < node[i].x) {
                    update(node[pos].y, dp[pos]);
                    pos++;
                }
                dp[i] = query(node[i].y - 1) + node[i].v;
                ans = max(ans, dp[i]);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    非常简洁,空间消耗很少,%%%

     

  • 相关阅读:
    移动平台的meta标签-----神奇的功效
    JAVA工程命名规范
    linux 查看tomcat 实时日志
    linux 配置全局jdk环境
    AJAX 前后端交互 验证信息是否正确
    数据库更新DATE类型的时间
    jq 克隆 移除table
    eclipse 安装javaEE插件 和htmlxmljsp编辑器
    oracle 正序 逆序 排序查询
    JQ遍历 input 并修改name属性
  • 原文地址:https://www.cnblogs.com/dilthey/p/9539618.html
Copyright © 2011-2022 走看看