[HDU 6447][YJJ's Salesman][2018CCPC网络选拔赛 1010][离散化+线段树+DP]

链接:

  http://acm.hdu.edu.cn/showproblem.php?pid=6447

题意:

  左上角(0,0),右下角(10^9,10^9)的网格,其中有n(1<=n<=10^5)个方格内有权值。

  一次只能沿右,下,右下三个方向走一个格子,只有沿右下方向走到格子里才可以获得权值。

  问从(0,0)到(10^9,10^9)的路径最大权值是多少。

思路:

  网格路径权值问题,第一感考虑DP,x从上往下,y从左往右刷表,状态转移方程为dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]+w[i][j]).

  存在两个问题:

  (1)坐标范围10^9,数组开不下

    离散化把坐标映射到[1,n],比如一维数组{1,100,10,10},先排序{1,10,10,100},然后离散化成{1,2,2,3}。

  (2)n的范围为1e5,O(n^2)的DP时空复杂度均爆表。

    联想背包问题的滚动数组,实际上我们可以只开一维数组,此时y需要从右往左刷表,状态转移方程为dp[j]=max(dp[j],dp[k]+w[i][j]),

    dp[k]是区间[1,j-1]最大值,区间最值查询显然可以用线段树以O(logn)的复杂度来处理,总体复杂度O(nlogn)。

  比赛时我怎么做不出来呢?菜到自闭orz~

代码:

  1 #include<bits/stdc++.h>
  2 #define rep(i,a,b) for (int i=a;i<=b;i++)
  3 using namespace std;
  4
  5 const int MAXN=(int)1e5+10;
  6
  7 struct Point{
  8   int x,y,w;
  9 } p[MAXN];
 10 int posHash[MAXN];
 11 void initHash(int n);
 12
 13 struct Node{
 14   int l,r,val;
 15 } tree[MAXN*4];
 16 void build(int id,int l,int r);
 17 void update(int id,int pos,int w);
 18 int query(int id,int L,int R);
 19
 20 int main()
 21 {
 22   int T;
 23   cin>>T;
 24   while (T--) {
 25     int n;
 26     scanf("%d",&n);
 27     rep(i,0,n-1) {
 28     scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].w);
 29     }
 30
 31     initHash(n);
 32     build(1,1,n);
 33
 34     int sum=0;
 35     rep(i,0,n-1) {
 36       int temp=p[i].w;
 37       if (p[i].y!=1) {
 38         temp+=query(1,1,p[i].y-1);
 39       }
 40       update(1,p[i].y,temp);
 41       sum=max(sum,temp);
 42     }
 43
 44     printf("%d\n",sum);
 45   }
 46   return 0;
 47 }
 48
 49 void initHash(int n)
 50 {
 51   sort(p,p+n,[](const Point &a,const Point &b)
 52              {return a.x<b.x;});
 53   posHash[0]=1;
 54   rep(i,1,n-1) {
 55     if (p[i].x==p[i-1].x) {
 56       posHash[i]=posHash[i-1];
 57     } else {
 58       posHash[i]=posHash[i-1]+1;
 59     }
 60   }
 61   rep(i,0,n-1) {
 62     p[i].x=posHash[i];
 63   }
 64
 65   sort(p,p+n,[](const Point &a,const Point &b)
 66              {return a.y<b.y;});
 67   posHash[0]=1;
 68   rep(i,1,n-1) {
 69     if (p[i].y==p[i-1].y) {
 70       posHash[i]=posHash[i-1];
 71     } else {
 72       posHash[i]=posHash[i-1]+1;
 73     }
 74   }
 75   rep(i,0,n-1) {
 76     p[i].y=posHash[i];
 77   }
 78
 79   sort(p,p+n,[](const Point &a,const Point &b)
 80              {return a.x==b.x? a.y>b.y : a.x<b.x;});
 81 }
 82
 83 void build(int id,int l,int r)
 84 {
 85   tree[id].l=l,tree[id].r=r;
 86   if (l==r) {
 87     tree[id].val=0;
 88     return;
 89   }
 90   int mid=(l+r)/2;
 91   build(id*2,l,mid);
 92   build(id*2+1,mid+1,r);
 93   tree[id].val=max(tree[id*2].val,tree[id*2+1].val);
 94 }
 95
 96 void update(int id,int pos,int w)
 97 {
 98   int l=tree[id].l,r=tree[id].r;
 99   if (l==r && r==pos) {
100     tree[id].val=max(tree[id].val,w);
101     return;
102   }
103   int mid=(l+r)/2;
104   if (pos<=mid) {
105     update(id*2,pos,w);
106   } else {
107     update(id*2+1,pos,w);
108   }
109   tree[id].val=max(tree[id*2].val,tree[id*2+1].val);
110 }
111
112 int query(int id,int L,int R)
113 {
114   int l=tree[id].l,r=tree[id].r;
115   if (L<=l && r<=R) {
116     return tree[id].val;
117   }
118   int mid=(l+r)/2;
119   if (R<=mid) {
120     return query(id*2,L,R);
121   } else if (mid<L) {
122     return query(id*2+1,L,R);
123   } else {
124     return max(query(id*2,L,mid),query(id*2+1,mid+1,R));
125   }
126 }

[HDU 6447][YJJ's Salesman][2018CCPC网络选拔赛 1010][离散化+线段树+DP]

原文地址:https://www.cnblogs.com/moonstviolet/p/9536209.html

时间: 2024-10-11 11:28:29

[HDU 6447][YJJ's Salesman][2018CCPC网络选拔赛 1010][离散化+线段树+DP]的相关文章

HDU6447 YJJ&#39;s Salesman 2018中国大学生程序设计竞赛 - 网络选拔赛1010 离散化+线段树+DP

YJJ's Salesman Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 253    Accepted Submission(s): 62 Problem Description YJJ is a salesman who has traveled through western country. YJJ is always on

HDU 6447 - YJJ&#39;s Salesman - [树状数组优化DP][2018CCPC网络选拔赛第10题]

Problem DescriptionYJJ 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 th

HDU 6441 - Find Integer - [费马大定理][2018CCPC网络选拔赛第4题]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6441 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Descriptionpeople in USSS love math very much, and there is a famous math problem .give you two integers n,a,

HDU 6447 YJJ’s Salesman (树状数组 + DP + 离散)

题意: 二维平面上N个点,从(0,0)出发到(1e9,1e9),每次只能往右,上,右上三个方向移动, 该N个点只有从它的左下方格点可达,此时可获得收益.求该过程最大收益. 分析:我们很容易就可以想到用DP,假设这个位置是相对上一个位置的方向而来,但是复杂度达到N^2 ,这样是不行的: 我们可以利用坐标的信息,将所有的点离散化后,以x优先按小到大排序,按y按大到小排序,这时维护一个DP(i) ,表示第I列的最值. j=0→i?1j=0→i?1                           d

2018中国大学生程序设计竞赛 - 网络选拔赛 1010 YJJ&#39;s Salesman 【离散化+树状数组维护区间最大值】

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6447 YJJ's Salesman Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 919    Accepted Submission(s): 290 Problem Description YJJ is a salesman who h

hdu 3016 Man Down (线段树 + dp)

题目大意: 是男人就下一般层...没什么可以多说的吧. 注意只能垂直下落. 思路分析: 后面求最大值的过程很容易想到是一个dp的过程 . 因为每一个plane 都只能从左边 从右边下两种状态. 然后我们所需要处理的问题就是 ,你如何能快速知道往左边下到哪里,往右边下到哪里. 这就是线段树的预处理. 讲线段按照高度排序. 然后按照高度从小到大加入到树中. 然后去寻找左端点 和 右端点最近覆盖的线段的编号. #include <cstdio> #include <iostream> #

HDU 5023 A Corrupt Mayor&#39;s Performance Art (据说是线段树)

题意:给定一个1-n的墙,然后有两种操作,一种是P l ,r, a 把l-r的墙都染成a这种颜色,另一种是 Q l, r 表示,输出 l-r 区间内的颜色. 析:应该是一个线段树+状态压缩,但是我用set暴力过去了.用线段树+状态压缩,区间更新,很简单,就不说了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #i

HDU 4509 湫湫系列故事——减肥记II(线段树-区间覆盖 或者 暴力技巧)

http://acm.hdu.edu.cn/showproblem.php?pid=4509 题目大意: 中文意义,应该能懂. 解题思路: 因为题目给的时间是一天24小时,而且还有分钟.为了解题方便,我们将小时换成分钟,那么一天24小时,总共有1440分钟.顾我就可以把一天里的任意HH:MM时间换成分钟.就这样一天的时间就变成[0,1440]区间了. 因为所给的活动最多是5*10^5,如果把活动的时间在线段[0,1440]都修改,那么时间的复杂度最坏是O(5*10^5*1440). (1)方法一

hdu 4521 小明系列问题——小明序列(线段树 or DP)

题目链接:hdu 4521 本是 dp 的变形,却能用线段树,感觉好强大. 由于 n 有 10^5,用普通的 dp,算法时间复杂度为 O(n2),肯定会超时.所以用线段树进行优化.线段树维护的是区间内包含某点的最大满足条件的长度,叶子节点以该元素结尾,最长长度.至于相邻两项隔 d 个位置,求 dp[i] 时,我们只把 dp[i - d - 1] 更新至线段树中,然后在这颗线段树中找最大的个数. 具体来说,就是把序列 S 的值 Ai 作为线段树叶子下标,以 Ai 结尾的 LIS 长度(即经典算法里