[SDOI2008]Sue的小球

做题时间:2022.9.26

\(【题目描述】\)

一个平面直角坐标系中有 \(N\) 个小球,第 \(i\) 个小球初始时位于 \((x_i,y_i)\),有一个速度 \(v_i\),每一秒会沿着 \(y\) 轴竖直想下掉 \(v_i\) 个单位,越过 \(x\) 轴后继续下掉。有一个人初始时位于 \((x_0,0)\) 处,每一秒可以向左或右移动一个单位,若移动到某个小球所在的与 \(x\) 轴垂直的直线上,则会捕获这个小球,获得的分数是此时小球的 \(y\) 坐标的千分之一。求在捕获所有小球的前提下能获得的最高分数。

\(【输入格式】\)

第一行两个整数 \(N,x_0\)

第二行 \(N\) 个整数 \(x_i\) 表示小球 \(i\)\(x\) 坐标

第三行 \(N\) 个整数 \(y_i\) 表示小球 \(i\)\(y\) 坐标

第四行 \(N\) 个整数 \(v_i\) 表示小球 \(i\) 的速度。

\(【输出格式】\)

一行一个保留三位小数的实数,表示答案。

\(【考点】\)

区间dp

\(【做法】\)

对于当前决策影响未来的情况,那么直接将对未来的影响计算金当前决策。

首先经过的点都是连续的,可以考虑区间dp,由于当前位置对状态转移有影响,因此定义 \(f_{i,j,0/1}\) 表示捕获完 \([l,r]\) 中的所有小球后停在 \(l\)\(r\) 的位置时的最大得分。

由于每次移动的时候所有未捕获的小球都会下落,因此可以提前减去它们的下落距离。定义 \(vs_i\) 表示速度的前缀和。

\[f_{i,j,0}=\max \begin{cases} f_{i+1,j,0}+y_i-(x_{i+1}-x_{i})\times (vs_n-vs_j+vs_i) \\ f_{i+1,j,1}+y_i-(x_j-x_i)\times (vs_n-vs_j+vs_i) \end{cases} \]

\[f_{i,j,1}=\max \begin{cases} f_{i,j-1,0}+y_j-(x_j-x_i)\times(vs_n-vs_{j-1}+vs_{i-1}) \\ f_{i,j-1,1}+y_j-(x_j-x_{j-1})\times(vs_n-vs_{j-1}+vs_{i-1}) \end{cases} \]

最后答案便是 \(\max(f_{1,n,0},f_{1,n,1})/1000\)

#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cmath>
#define int long long
using namespace std;
typedef long long ll;
const int N=1e3+50;
struct egg{
	int x,y,v;
}a[N];
int n,sx;
int vs[N];
ll f[N][N][2];
bool cmp(egg p,egg q){return p.x<q.x;}
signed main()
{
	scanf("%lld%lld",&n,&sx);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i].x);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i].y);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i].v);
	sort(a+1,a+1+n,cmp);
	
	for(int i=1;i<=n;i++) vs[i]=vs[i-1]+a[i].v;
	for(int i=1;i<=n;i++) f[i][i][0]=f[i][i][1]=a[i].y-abs(sx-a[i].x)*vs[n];//初始化
	
	for(int len=2;len<=n;len++){
		for(int i=1;i<=n-len+1;i++){
			int j=i+len-1;
			f[i][j][0]=max(f[i+1][j][0]+a[i].y-(ll)(a[i+1].x-a[i].x)*(vs[n]-vs[j]+vs[i]),
						f[i+1][j][1]+a[i].y-(ll)(a[j].x-a[i].x)*(ll)(vs[n]-vs[j]+vs[i]));
			
			f[i][j][1]=max(f[i][j-1][0]+a[j].y-(ll)(a[j].x-a[i].x)*(vs[n]-vs[j-1]+vs[i-1]),
						f[i][j-1][1]+a[j].y-(ll)(a[j].x-a[j-1].x)*(vs[n]-vs[j-1]+vs[i-1])); 
		}
	}
	printf("%.3lf\n",max(f[1][n][0],f[1][n][1])/1000.0);
	return 0;
}
posted @ 2022-09-26 22:26  lxzy  阅读(34)  评论(0)    收藏  举报