【BZOJ1560】【JSOI2009】火星藏宝图 [DP]
火星藏宝图
Time Limit: 10 Sec Memory Limit: 64 MB[Submit][Status][Discuss]
Description
Input
Output
Sample Input
4 10
1 1 20
10 10 10
3 5 60
5 3 30
1 1 20
10 10 10
3 5 60
5 3 30
Sample Output
-4
HINT
1<= M <=2000, 2<= N <=100000.
Main idea
每个点上有一个收益,从一个点走到另外一个点的花费是欧几里得距离的平方,问从(1,1)走到(m,m)的最大收益。
Solution
首先,运用DP。而且若A < C < B,显然则有 (A-B)^2 > (A-C)^2 + (C-B)^2。
那么我们对横坐标排序一下,可以保证横向的大小关系。然后对于一个转移,每一纵向只有最接近它的点有用。这样就可以做到O(nm)了。
Code
1 #include<iostream>
2 #include<string>
3 #include<algorithm>
4 #include<cstdio>
5 #include<cstring>
6 #include<cstdlib>
7 #include<cmath>
8 using namespace std;
9 typedef long long s64;
10
11 const int ONE = 500005;
12 const int INF = 2147483640;
13
14 int n,m;
15 int pos[ONE];
16 int f[ONE];
17
18 struct power
19 {
20 int x,y,z;
21 }a[ONE];
22
23 bool cmp(const power &a, const power &b)
24 {
25 if(a.x != b.x) return a.x < b.x;
26 return a.y < b.y;
27 }
28
29 int cost(int Ax, int Ay, int Bx, int By)
30 {
31 return (Ax - Bx) * (Ax - Bx) + (Ay - By) * (Ay - By);
32 }
33
34 int get()
35 {
36 int res=1,Q=1;char c;
37 while( (c=getchar())<48 || c>57 )
38 if(c=='-')Q=-1;
39 res=c-48;
40 while( (c=getchar())>=48 && c<=57 )
41 res=res*10+c-48;
42 return res*Q;
43 }
44
45 int main()
46 {
47 n = get(); m = get();
48 for(int i=1; i<=n; i++)
49 a[i].x = get(), a[i].y = get(), a[i].z = get();
50 sort(a+1, a+n+1, cmp);
51
52 memset(f, -127, sizeof(f));
53 pos[1] = 1; f[1] = 0;
54 for(int id=1; id<=n; id++)
55 {
56 int x = a[id].x, y = a[id].y;
57 int record = -INF;
58 for(int j=1; j<=y; j++)
59 if(pos[j])
60 record = max( record, f[j] - cost(pos[j],j, x,y) );
61
62 pos[y] = x;
63 f[y] = record + a[id].z;
64 }
65
66 printf("%d", f[m]);
67 }
68