BZOJ 1560 JSOI2009 火星藏宝图 动态规划

题目大意:给定一个m*m的矩阵,上面有n个点,每个点上有一个正的收益,在两个点之间走的代价是距离的平方,求(1,1)到(m,m)的最大收益

直接排序并且DP的方法很容易想到 但是显然O(n^2)过不去

考虑平方的特性 由于A和B都大于等于0时(A+B)^2>=A^2+B^2 因此A->B->C一定比A->C更优

根据这个特性,我们可以将点按照纵坐标为第一键值,横坐标为第二键值排序

对于每一列我们维护一个当前纵坐标最大的点 用这个点更新一定比它下面的点更新更优

因此对于每个点枚举横坐标比它小的列更新即可 时间复杂度O(nm) 大概2E左右

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
struct Point{
	int x,y,z,f;
	friend istream& operator >> (istream& _,Point &p)
	{
		scanf("%d%d%d",&p.x,&p.y,&p.z);
		p.f=-INF;
		return _;
	}
	bool operator < (const Point &p) const
	{
		if(y!=p.y)
			return y<p.y;
		return x<p.x;
	}
	friend int Distance(const Point &p1,const Point &p2)
	{
		return (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y);
	}
	void Update(const Point &p)
	{
		f=max(f,p.f-Distance(p,*this)+z);
	}
}points[200200];
int n,m;
Point *now[1010];
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("1560.in","r",stdin);
	#endif
	int i,j;
	cin>>n>>m;
	for(i=1;i<=n;i++)
		cin>>points[i];
	sort(points+1,points+n+1);
	points[1].f=points[1].z;
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=points[i].x;j++)
			if(now[j])
				points[i].Update(*now[j]);
		now[j-1]=&points[i];
	}
	cout<<points[n].f<<endl;
	return 0;
}
时间: 2024-10-12 14:41:55

BZOJ 1560 JSOI2009 火星藏宝图 动态规划的相关文章

BZOJ 1560 火星藏宝图(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1560 题意: 思路:f[i]表示到达i的最大收益.这样是 O(n^2)的.我们考虑,由于转移的条件,a^2+b^2<(a+b)^2,因此对于三个点A.B.C.若A能到B,B能到C,那么A也能到C, 但是不如经过B更好.因此,我们记录到达第j列最靠下的i即可.那么转移(x,y)时,用记录的前y列即可. struct node { int x,y,w; }; node a[N]; int

【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 Sample Output -4 HINT 1<= M <=2000, 2<= N <=100000. Main idea 每个点上有一个收益,从一个点走到另外一个点的花费是欧几里得距离的平方,问从

BZOJ 1452: [JSOI2009]Count (二维树状数组)

Description Input Output Sample Input Sample Output 1 2 HINT 二维树状数组的简单应用,c数组的第一维坐标相当于哈希.如果是修改操作,修改前 将当前的值的个数以及祖先都减1, 修改后将个数加1. #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <set> #include

[BZOJ 2257][JSOI2009]瓶子和燃料 题解(GCD)

[BZOJ 2257][JSOI2009]瓶子和燃料 Description jyy就一直想着尽快回地球,可惜他飞船的燃料不够了. 有一天他又去向火星人要燃料,这次火星人答应了,要jyy用飞船上的瓶子来换.jyy 的飞船上共有 N个瓶子(1<=N<=1000) ,经过协商,火星人只要其中的K 个 . jyy 将 K个瓶子交给火星人之后,火星人用它们装一些燃料给 jyy.所有的瓶子都没有刻度,只 在瓶口标注了容量,第i个瓶子的容量为Vi(Vi 为整数,并且满足1<=Vi<=10000

BZOJ 1560 火星藏宝图(DP)

思路:发现如果从A能到B,B能到C,那么一定A能到C,且根据不等式:A^2+B^2<=(A+B)^2,而且权值没有负数,因此经过B比不经过B要优,因此,我们从左上到右下做,每一列,我们只记录之前做过的最下面的那个位置的信息,然后从这个位置的前几列里面寻找最优. 1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iost

bzoj 4033 树上染色 - 树形动态规划

有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑 色,并将其他的N-K个点染成白色.将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的 收益.问收益最大值是多少. Input 第一行两个整数N,K. 接下来N-1行每行三个正整数fr,to,dis,表示该树中存在一条长度为dis的边(fr,to). 输入保证所有点之间是联通的. N<=2000,0<=K<=N Output 输出一个正整数,表示收益的最大值. Sampl

bzoj 1449 [JSOI2009]球队收益(费用拆分,最小费用流)

1449: [JSOI2009]球队收益 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 547  Solved: 302[Submit][Status][Discuss] Description Input Output 一个整数表示联盟里所有球队收益之和的最小值. Sample Input 3 3 1 0 2 1 1 1 10 1 0 1 3 3 1 2 2 3 3 1 Sample Output 43 HINT Source [思路] 费用拆分,

BZOJ 1559: [JSOI2009]密码( AC自动机 + 状压dp )

建AC自动机后, dp(x, y, s)表示当前长度为x, 在结点y, 包括的串的状态为s的方案数, 转移就在自动机上走就行了. 对于输出方案, 必定是由给出的串组成(因为<=42), 所以直接暴搜答案. 数据范围很小, 可以AC(复杂度懒得算了....) ------------------------------------------------------------------------------------------------ #include<cstdio> #in

BZOJ 1449: [JSOI2009]球队收益( 最小费用最大流)

先考虑假如全部输了的收益. 再考虑每场比赛球队赢了所得收益的增加量,用这个来建图.. -------------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<iostre