[SDOI2008]Sue的小球

XXIX.[SDOI2008]Sue的小球

DP做多了,手感自然就出来了。

话说这题打着“小球”的名字题目中却是“彩蛋”是怎么回事

首先,这个下落速度v,尽管题面中说它可能为负数,但我们想一想,这可能吗?如果是负数答案就是正无穷(可以等着这个球一直向上飞),因此排除球速为负的可能。

如果是这样的话,那么,当我们经过一个球时,随手将它射爆明显是更好的行为。因此,无论何时,我们球已经被射下的位置一定是一个包含起始点x0的区间。

我们将所有球按照位置在x0左边还是右边压进两个vector中(下标从0开始)。在左边的vector(设为v1)中,我们按照x值从大到小排序并处理;在右边(设为v2),我们从小到大排序。同时,我们在v1v2中都压入一个x=x0的球,方便初始化。

我们设f[i][j][0/1]表示:当前进行到v1的第i位,v2的第j位,同时位于这个区间的左/右端点的情况。我们可以提前计算出所有小球初始y值的和,这样我们只需要最小化捡球过程中球下落的距离即可。

我们设s[i][j]表示:除了v1i位和v2j位外,其它球1s内下落的距离之和(这借鉴了XII.任务安排费用提前计算的经典思想)。在实现中,这个可以直接通过前缀和做出。设x1[i]表示v1x值,x2[j]表示v2x值。

我们有

f[i][j][0]=f[i1][j][0]+|x1[i1]x1[i]|(s[i1][j])

f[i][j][1]=f[i][j1][0]+|x2[j1]x2[j]|(s[i][j1])

然后因为两边可以互相走,所以还有

f[i][j][0]=f[i][j][1]+|x2[j]x1[i]|s[i][j]

f[i][j][1]=f[i][j][0]+|x1[i]x2[j]|s[i][j]

两种转移取min即可。

复杂度O(n2)

代码:

#include<bits/stdc++.h>
using namespace std;
int n,X,s1[1010],s2[1010],sy,f[1010][1010][2],sv;
struct node{
	int x,y,v;
	node(int a=0,int b=0,int c=0){x=a,y=b,v=c;}
}b[1010];
vector<node>v1,v2;
bool cmp1(const node &x,const node &y){
	return x.x<y.x;
}
bool cmp2(const node &x,const node &y){
	return x.x>y.x;
}
int main(){
	scanf("%d%d",&n,&X),memset(f,0x3f3f3f3f,sizeof(f));
	for(int i=1;i<=n;i++)scanf("%d",&b[i].x);
	for(int i=1;i<=n;i++)scanf("%d",&b[i].y),sy+=b[i].y;
	for(int i=1;i<=n;i++)scanf("%d",&b[i].v);
	for(int i=1;i<=n;i++){
		if(b[i].x<X)v1.push_back(b[i]);
		if(b[i].x>X)v2.push_back(b[i]);
	}
	v1.push_back(node(X,0,0)),v2.push_back(node(X,0,0));
	sort(v1.begin(),v1.end(),cmp2);
	sort(v2.begin(),v2.end(),cmp1);
	for(int i=1;i<v1.size();i++)s1[i]=s1[i-1]+v1[i].v;
	for(int i=1;i<v2.size();i++)s2[i]=s2[i-1]+v2[i].v;
//	for(int i=0;i<v1.size();i++)printf("%d %d %d\n",v1[i].x,v1[i].y,v1[i].v);puts("");
//	for(int i=0;i<v2.size();i++)printf("%d %d %d\n",v2[i].x,v2[i].y,v2[i].v);puts("");
	sv=s1[v1.size()-1]+s2[v2.size()-1];
	f[0][0][0]=f[0][0][1]=0;
	for(int i=0;i<v1.size();i++)for(int j=0;j<v2.size();j++){
		if(i)f[i][j][0]=f[i-1][j][0]+abs(v1[i].x-v1[i-1].x)*(sv-s1[i-1]-s2[j]);
		if(j)f[i][j][1]=f[i][j-1][1]+abs(v2[j].x-v2[j-1].x)*(sv-s1[i]-s2[j-1]);
		f[i][j][0]=min(f[i][j][0],f[i][j][1]+abs(v2[j].x-v1[i].x)*(sv-s1[i]-s2[j]));
		f[i][j][1]=min(f[i][j][1],f[i][j][0]+abs(v1[i].x-v2[j].x)*(sv-s1[i]-s2[j]));
	}
	double res=sy-min(f[v1.size()-1][v2.size()-1][0],f[v1.size()-1][v2.size()-1][1]);
	res/=1000;
	printf("%.3lf\n",res);
	return 0;
}

posted @   Troverld  阅读(43)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示