题目链接:bzoj1560
题目大意:
有一个
M×M
的矩阵,
n
个岛,每个岛上有一定的价值。要从(1,1)到(m,m),只能往右下方走。问收益的最大值。
收益=得到的总价值和-总体力消耗
从一个岛(x1,y1)到另一个岛(x2,y2)的体力消耗=
题解:
贪心思想的维护的嗯dp?
对于一个点
A(x,y)
,如果它的左上方有
B(x1,y1)
,
C(x1,y2)
,
y1<y2
,根据
a2+b2≤(a+b)2
可知从
B→A
必不会优于
B→C→A
。
即对于一个点 A 之前的每一列,只有行最靠近
设
pos[i]
表示第
i
列最靠下那行的位置,
以 行 为第一关键值,列 为第二关键值排序。
这样枚举列的时候,就保证了行是一定比这个点小的。
直接更新就好了。
膜栋爷爷用斜率优化来优化,并不懂怎么写方程先膜了再说。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 2001000
#define maxm 1100
const int inf=1e9;
struct node
{
int x,y,c;
}a[maxn];
int pos[maxm],f[maxm];
//pos[i]表示第i列最靠下那行的位置
//f[i]表示(pos[i],i)的值
int mymax(int x,int y){return (x>y)?x:y;}
bool cmp(node x,node y) {if (x.x!=y.x) return x.x<y.x;return x.y<y.y;}
int cal(int x1,int y1,int x2,int y2){return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int i,j,n,m;
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c);
sort(a+1,a+1+n,cmp);
f[1]=0;pos[1]=1;
for (i=1;i<=n;i++)
{
int ls=-inf;
for (j=1;j<=a[i].y;j++) if (pos[j])
ls=mymax(ls,f[j]-cal(a[i].x,a[i].y,pos[j],j));
pos[a[i].y]=a[i].x;f[a[i].y]=ls+a[i].c;
}
printf("%d\n",f[m]);
return 0;
}