斜率优化+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; }