(ball.pas/c/cpp,限时0.5 秒,内存256M)
【题目描述】
Sue 和Sandy 最近迷上了一个电脑游戏,这个游戏的故事发在美丽神秘并且充满刺
激的大海上,Sue 有一支轻便小巧的小船。然而,Sue 的目标并不是当一个海盗,而是
要收集空中漂浮的彩蛋,Sue 有一个秘密武器,只要她将小船划到一个彩蛋的正下方,
然后使用秘密武器便可以在瞬间收集到这个彩蛋。然而,彩蛋有一个魅力值,这个魅力
值会随着彩蛋在空中降落的时间而降低,Sue 要想得到更多的分数,必须尽量在魅力值
高的时候收集这个彩蛋,而如果一个彩蛋掉入海中,它的魅力值将会变成一个负数,但
这并不影响Sue 的兴趣,因为每一个彩蛋都是不同的,Sue 希望收集到所有的彩蛋。
然而Sandy 就没有Sue 那么浪漫了,Sandy 希望得到尽可能多的分数,为了解决这
个问题,他先将这个游戏抽象成了如下模型:
以Sue 的初始位置所在水平面作为x 轴。
一开始空中有N 个彩蛋,对于第i 个彩蛋,他的初始位置用整数坐标(xi, yi)表
示,游戏开始后,它匀速沿y 轴负方向下落,速度为vi 单位距离/单位时间。Sue 的初始
位置为(x0, 0),Sue 可以沿x 轴的正方向或负方向移动,Sue 的移动速度是1 单位距离
/单位时间,使用秘密武器得到一个彩蛋是瞬间的,得分为当前彩蛋的y 坐标的千分之
一。
现在,Sue 和Sandy 请你来帮忙,为了满足Sue 和Sandy 各自的目标,你决定在收
集到所有彩蛋的基础上,得到的分数最高。
【输入文件】
第一行为两个整数N, x0 用一个空格分隔,表示彩蛋个数与Sue 的初始位置。
第二行为N 个整数xi,每两个数用一个空格分隔,第i 个数表示第i 个彩蛋的初始
横坐标。
第三行为N 个整数yi,每两个数用一个空格分隔,第i 个数表示第i 个彩蛋的初始
纵坐标。
第四行为N 个整数vi,每两个数用一个空格分隔,第i 个数表示第i 个彩蛋匀速沿
y 轴负方向下落的的速度。
【输出文件】
一个实数,保留三位小数,为收集所有彩蛋的基础上,可以得到最高的分数。
【样例】
输入样例(ball.in 的内容):
3 0
-4 -2 2
22 30 26
1 9 8
输出样例(ball.out 的内容):
0.000
【数据范围】
N<=20,对于30%的数据。
N<=1000,对于100%的数据。
-10^4 <= xi,yi,vi <= 10^4,对于100%的数据。
动态规划
首先可以明确的是可以将x0左边和右边的彩蛋分组
按距离x0距离的顺序排序,存入两个队列中
y之和为最多达到的分数
用f[0][i][j]表示当前在队列1的i位置,队列2已该走j位置的分数减小最小值
用f[1][i][j]表示当前在队列2的j位置,队列1已该走i位置的分数减小最小值
转移方程为
f[0,i,j]=min(f[0,i-1,j]+(w1[i]+w2[j])*(s1[i-1].x-s1[i].x),f[1,i,j-1]+(w1[i]+w2[j])*(s2[j-1].x-s1[i].x))
f[1,i,j]=min(f[0,i-1,j]+(w1[i]+w2[j])*(s2[j].x-s1[i-1].x),f[1,i,j-1]+(w1[i]+w2[j])*(s2[j].x-s2[j-1].x))
当前在y坐标之和减去min(<当前在队列1队尾,队列2已走完的分数减小最小值>,<当前在队列2队尾,队列1已走完的分数减小最小值>)
测试数据
http://mail.qq.com/cgi-bin/ftnExs_download?k=716635352cf2cbcd6241402a1865011d065605050755041d1800020354500002554b0c0652541906555f0c180f5057011a560707045306510257000c00653c3255075959191755403720&t=exs_ftn_download&code=7f557e42
program ball;
const
thu:int64=1000;
type
point=record
x,v:longint;
end;
var
n,x0,i,j,k,t1,t2,d1,d2:longint;
ans:int64;
s1,s2,bal:array [0..1001] of point;
f:array [0..1,0..1001,0..1001] of int64;
w1,w2:array [0..1001] of int64;
procedure swap (var a,b:point);
var
i:point;
begin
i:=a;
a:=b;
b:=i;
end;
procedure qsort (s,e:longint);
var
i,j,k:longint;
begin
if s>=e then exit;
i:=s;
j:=e;
k:=bal[(s+e) div 2].x;
while i<=j do
begin
while bal[i].x<k do inc(i);
while bal[j].x>k do dec(j);
if i>j then break;
swap(bal[i],bal[j]);
inc(i);
dec(j);
end;
qsort(s,j);
qsort(i,e);
end;
begin
assign(input,'ball.in');
reset(input);
assign(output,'ball.out');
rewrite(output);
read(n,x0);
ans:=0;
for i:=1 to n do
read(bal[i].x);
for i:=1 to n do
begin
read(k);
ans:=ans+k;
end;
for i:=1 to n do
read(bal[i].v);
qsort(1,n);
t1:=0;
d1:=0;
for i:=n downto 1 do
if bal[i].x<x0 then
begin
if (t1>0)and(bal[i].x=s1[t1].x) then
s1[t1].v:=s1[t1].v+bal[i].v
else
begin
inc(t1);
s1[t1]:=bal[i];
end;
d1:=d1+bal[i].v;
end;
t2:=0;
d2:=0;
for i:=1 to n do
if bal[i].x>x0 then
begin
if (t2>0)and(bal[i].x=s2[t2].x) then
s2[t2].v:=s2[t2].v+bal[i].v
else
begin
inc(t2);
s2[t2]:=bal[i];
end;
d2:=d2+bal[i].v;
end;
fillchar(f,sizeof(f),63);
s1[0].x:=x0;
for i:=t1 downto 0 do
w1[i]:=w1[i+1]+s1[i].v;
for i:=t2 downto 1 do
w2[i]:=w2[i+1]+s2[i].v;
s1[t1+1].x:=s1[t1].x;
s2[t2+1].x:=s2[t2].x;
f[0,0,1]:=0;
for i:=0 to t1+1 do
for j:=1 to t2+1 do
begin
if (i=t1+1)and(j=t2+1) then continue;
if (i<>t1+1)and(i>0)and(f[0,i,j]>f[0,i-1,j]+(w1[i]+w2[j])*(s1[i-1].x-s1[i].x)) then
f[0,i,j]:=f[0,i-1,j]+(w1[i]+w2[j])*(s1[i-1].x-s1[i].x);
if (j<>t2+1)and(i>0)and(f[1,i,j]>f[0,i-1,j]+(w1[i]+w2[j])*(s2[j].x-s1[i-1].x)) then
f[1,i,j]:=f[0,i-1,j]+(w1[i]+w2[j])*(s2[j].x-s1[i-1].x);
if (i<>t1+1)and(j>1)and(f[0,i,j]>f[1,i,j-1]+(w1[i]+w2[j])*(s2[j-1].x-s1[i].x)) then
f[0,i,j]:=f[1,i,j-1]+(w1[i]+w2[j])*(s2[j-1].x-s1[i].x);
if (j<>t2+1)and(j>1)and(f[1,i,j]>f[1,i,j-1]+(w1[i]+w2[j])*(s2[j].x-s2[j-1].x)) then
f[1,i,j]:=f[1,i,j-1]+(w1[i]+w2[j])*(s2[j].x-s2[j-1].x);
end;
if ans-f[0,t1,t2+1]>ans-f[1,t1+1,t2] then ans:=ans-f[0,t1,t2+1]
else ans:=ans-f[1,t1+1,t2];
writeln(ans/1000:0:3);
close(input);
close(output);
end.