bzoj1492

斜率优化+cdq分治

这个就是都不单调的情况

dp[i] = max(a[i] * x[j] + b[i] * y[j])

x[j] 表示能买多少a劵 y[j]表示能买多少b劵

化简一下 dp[i] / b[i] = max(a[i] / b[i] * x[j] + y[j])

非常标准的斜率优化形式 

-(a[i] / b[i]) * x[j] + dp[i] / b[i] = y[j]

可惜-(a[i] / b[i]) 和 y[j] 都不单调 那么我们就得用cdq分治和二分 然而二分可以通过排序优化掉

我们先按-(a[i] / b[i]) 排序 

然后cdq分治,每次先按编号分成两块 cdq左边

现在左边的dp值已经得出 并且按照x[j] 排序

那么我们可以直接左边构成凸包 因为右边还是-(a[i] / b[i]) 经过排序后单调 所以我们可以像普通斜率优化一样做一遍

更新完之后我们再cdq右边

最后两边按x归并

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const double eps = 1e-9;
int n, top;
struct data {
    int id;
    double a, b, x, y, k, rate;
    bool friend operator < (const data &a, const data &b) {
        return a.k > b.k;
    }
} a[N], t[N];
double dp[N];
int st[N];
double slope(int i, int j)
{
//  if(!i || !j) return -1e20;
    if(fabs(a[i].x - a[j].x) < eps) return 1e20;
    return (a[i].y - a[j].y) / (a[i].x - a[j].x);
}
void cdq(int l, int r)
{
    if(l == r) 
    {
        dp[l] = max(dp[l], dp[l - 1]);
        a[l].y = dp[l] / (a[l].a * a[l].rate + a[l].b);
        a[l].x = a[l].y * a[l].rate;
        return; 
    }
    int mid = (l + r) >> 1, p1 = l, p2 = mid + 1;
    for(int i = l; i <= r; ++i) if(a[i].id <= mid) t[p1++] = a[i]; else t[p2++] = a[i];
    for(int i = l; i <= r; ++i) a[i] = t[i];
    cdq(l, mid);
    top = 0;
    for(int i = l; i <= mid; ++i) 
    {
        while(top > 1 && slope(st[top], st[top - 1]) < slope(st[top], i) + eps) --top;
        st[++top] = i;
    }
    int j = 1;
//  st[++top] = 0;
    for(int i = mid + 1; i <= r; ++i) 
    {
        while(j < top && slope(st[j], st[j + 1]) + eps > a[i].k) ++j;
        dp[a[i].id] = max(dp[a[i].id], a[st[j]].x * a[i].a + a[st[j]].y * a[i].b);
    } 
    cdq(mid + 1, r);
    int p = l;
    p1 = l;
    p2 = mid + 1;
    while(p1 <= mid && p2 <= r) if(a[p1].x < a[p2].x || (fabs(a[p1].x - a[p2].x) < eps && a[p1].y < a[p2].y)) t[p++] = a[p1++]; else t[p++] = a[p2++];
    while(p1 <= mid) t[p++] = a[p1++];
    while(p2 <= r) t[p++] = a[p2++];
    for(int i = l; i <= r; ++i) a[i] = t[i];
}
int main()
{
//  freopen("cash.in", "r", stdin);
//  freopen("cash.out", "w", stdout);
    scanf("%d%lf", &n, &dp[0]);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%lf%lf%lf", &a[i].a, &a[i].b, &a[i].rate);
        a[i].k = -a[i].a / a[i].b;
        a[i].id = i;
    }
    sort(a + 1, a + n + 1);
    cdq(1, n);
//  for(int i = 1; i <= n; ++i) printf("dp[%d] = %.3f\n", i, dp[i]);
    printf("%.3f\n", dp[n]);
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}
View Code

 

posted @ 2018-01-14 21:30  19992147  阅读(96)  评论(0编辑  收藏  举报