Description
有(N+1)个平行于y轴的河岸排成一排,每两个河岸之间夹着一条河,所以一共有N条河。第i 条河的宽度为wi,ryz在第i 条河中行进的速度为vi。河岸的宽度忽略不计。令X=sigma(wi)。
规定:
1、ryz从(0,0)出发,终点是(X,Y)。Y是一个给定的整数。
2、ryz在渡河时,必须从一个整点驶向另一个整点,花费的时间为这两个点的欧几里得距离除以速度。
3、ryz可以在河岸上行走,但也是必须从一个整点走向另一个整点,速度为给定的u。
求花费时间的最小值。
Input
第一行三个正整数N,Y,u。
第二行N个正整数表示wi。
第三行N个正整数表示vi。
Output
输出一行答案,保留4位小数。
Sample Input
2 3 1
5 5
1 1
Sample Output
10.4842
Data Constraint
对于30%的数据,N<=50,Y<=500;
对于60%的数据,N<=50;
对于100%的数据,N<=50000;
对于100%的数据,u<=10^5,wi<=10^5,vi<=10^5,Y<=10^5。
Hint
样例解释
Ryz先从(0,0)渡过第一条河到达(5,1),花费时间为5.0990,然后渡过第二条河到达(10,3),花费时间为5.3852。
先到(5,2)再到(10,3)也一种最优解。
分析
如果现在让你找一条路线(不一定最优),你一定会选择先向下走过N行后向右走到第Y列,如图。总时间可以马上计算出来。
这时候如果将路线分段,每一段为路线中其中一行到下一行的路线,可以考虑让其中一段路稍稍改变,让总时间减少。为什么要这样考虑?因为改变这一段路线其实并不改变其他N-1段路线的长度以及时间(显然)。怎么改变?当然是将下一行上的端点向右移动1个单位(为什么不能向左移动?显然这只会增加时间):
这样改变对总时间的影响是多少呢?因为上图中这条绿色的倾斜的路线实际上替代了2段粉色的路线,因此对总时间的增加或减少是可以计算出来的(怎么计算??可以用走绿色斜线的时间减去走原路线即2段粉色路线的时间)。如果总时间减少了那么这次路线改变就是成功的。对于N段路线我们都可以考虑这样的改变,最多可以改变Y次(为什么?请仔细思考)。
那么一个基于贪心思想的解法就出来了:每一次在N段路线中选择1条改变路线后对总时间影响最大的路线进行改变,直至改变了Y次或者没有能减少时间的改变为止。由于实际上要在N个数中找一个最小的数并且进行修改,因此可以用一个堆维护这N个数,在O(logN)的时间内就可以完成一次修改,总的时间复杂度为O(YlogN)。
代码
#include <bits/stdc++.h>
int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
struct NOTE
{
double t;
int x,y,z;
bool operator < (NOTE a) const
{
return a.t < t;
}
};
const int N = 50005;
int w[N],v[N];
int y,u,n;
double ans;
std::priority_queue <NOTE> Q;
double getDis(double x, double y)
{
return sqrt(x * x + y * y);
}
int main()
{
n = read(), y = read(), u = read();
for (int i = 1; i <= n; i++)
w[i] = read();
for (int i = 1; i <= n; i++)
v[i] = read();
NOTE p;
ans = 0;
for (int i = 1; i <= n; i++)
{
ans += w[i] / (double)v[i];
p.t = (getDis(w[i], 1) - w[i]) / (double)v[i];
p.x = w[i], p.y = 0, p.z = v[i];
Q.push(p);
}
p.t = 1 / double(u);
p.x = 0, p.y = 0, p.z = u;
Q.push(p);
for (int i = 1; i <= y; i++)
{
p = Q.top(), Q.pop();
ans += p.t;
p.y++;
p.t = (getDis(p.x, p.y + 1) - getDis(p.x, p.y)) / (double)p.z;
Q.push(p);
}
printf("%.4f\n",ans);
}