按照http://hzwer.com/3508.html改的……
勉强能当自己板子用吧…… 感觉细节好多,
要注意各种细节,比如两个点重合啊,两个点的斜率不存在啊种种种种……
太累了,但是我感觉判断2个点斜率差,可以用我的方法更好一些~
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int maxn = 100005;
const double inf = 1e12;//-inf就是负无穷了
const double eps = 1e-9;
double f[maxn]={0};
struct node
{
int id;
double x, y, k;
double a, b, r;
}p[maxn], t[maxn];
node stk[maxn];
int top, n;
bool operator <(node A, node B)//斜率倒着排序,为了在凸壳上计算方便
{
return A.k > B.k;
}
bool check(node A, node B, node C)// A,B的斜率如果<=B,C斜率,则为true
{
double a=(B.y-A.y)*(C.x-B.x);
double b=(C.y-B.y)*(B.x-A.x);
if (a==b) return true;
if (a>0 && b>0) return a>b;
if (a<0 && a<0) return a<b;
if (a<0) return true;
return false;
}
double xie(node A, node B)
{
if (A.y==B.y) return inf;
return (A.y-B.y)/(A.x-B.x);
}
double getDP(int k, node A)
{
return p[k].a*A.x +p[k].b*A.y;
}
void solve(int l, int r)
{
if (l == r)
{
f[l]=max(f[l],f[l-1]);
p[l].y=f[l]/(p[l].a*p[l].r+p[l].b);
p[l].x=p[l].r*p[l].y;
return;
}
int mid = l + (r-l)/2;
int l1 =l, l2 = mid + 1;
for (int i = l; i <=r; ++ i)
if (p[i].id <= mid) t[l1++] = p[i];
else t[l2++] = p[i];
for (int i = l; i <= r; ++ i) p[i] = t[i];
solve(l, mid);
top = 0;//[a[top]为栈顶元素,top=0表示空栈,栈内有0个元素。]
//开始做一次凸壳,之前的所有的点,都是按照x坐标排序好了,因为已经不需要求解其f值,已经不需要管顺序了
node tmp;
for (int i = l; i<= mid; ++ i)
{
while (top > 1 && check(stk[top- 1], stk[top], p[i])) top--;
stk[++top] = p[i];
}
tmp;
tmp.x=0;
tmp.y=0;
stk[++top]=tmp;//为了让最后一个节点出现异常,即位最后一个斜率巨大无比是正数。而递减的序列出现正数,不可能更优
int pos=1;
for (int i = mid + 1; i <= r; ++ i)
{
while (pos <=top && getDP(i, stk[pos]) <= getDP(i, stk[pos+1])) pos++;
f[p[i].id] = max(f[p[i].id], getDP(i, stk[pos]));
}
solve(mid + 1, r);
l1=l, l2=mid+1;
//现在已经计算完l,r区间的所有值,并且实际上,已经都取得最优解了。需要给他们按照x坐标,归并排序了
for (int i = l; i <= r; ++ i)
if (l2 > r|| l1 <=mid && (p[l1].x < p[l2].x || p[l1].x==p[l2].x && p[l1].y>p[l2].y)) t[i] = p[l1++];
else t[i] = p[l2++];
for (int i = l; i <=r; ++ i) p[i] = t[i];
}
int main()
{
freopen("cash.in","r",stdin);
freopen("cash.ans","w",stdout);
scanf("%d%lf",&n, &f[0]);
for (int i = 1; i <= n; ++ i)
{
scanf("%lf%lf%lf", &p[i].a, &p[i].b, &p[i].r);
p[i].id = i;
p[i].k = -p[i].a/p[i].b;
if (p[i].a==0) p[i].k=0;
}
sort(p + 1, p + 1 + n);
solve(1, n);
printf("%.3lf\n", f[n]);
return 0;
}