首先
推荐一篇博客:CDQ和整体二分
建议在学CDQ之前和学完CDQ之后都看一看,这个总结得十分的到位;
我当时就是刚学CDQ,网上题解看不懂,看了这篇博客后就自己YY出来了。
题目链接:BZOJ1492
分析
1. 显然,有便宜尽量去占,没便宜一点也不碰,要买就买到没钱,要卖就卖光,才是最优解。
2. 设
dp[i]
为到第
i
天为止,最多能赚多少钱,
3. 考虑斜率优化,设
g[j,k]=(X[j]−X[k])/(Y[j]−Y[k])
,维护凸壳,由于
Y
不单调,所以有两种方法:1. splay维护;2. CDQ分治。这里选择用CDQ分治。
4. 由于要维护
5. 在用
上代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef double DB;
const DB EPS = 1e-6;
const int N = 12e4 + 10;
const int INF = 0x3f3f3f3f;
int n;
DB R[N], A[N], B[N];
DB dp[N], X[N], Y[N];
int id[N];
inline bool cmpId(int a, int b) {
return (-B[a] / A[a]) > (-B[b] / A[b]);
}
void init() {
scanf("%d %lf", &n, &dp[1]);
for (int i = 1; i <= n; i++)
scanf("%lf %lf %lf", &A[i], &B[i], &R[i]), id[i] = i;
sort(id + 1, id + n + 1, cmpId);
}
int ary[N];
void mergeSort(int l, int r) {
int mid = (l + r) >> 1;
int ll = l, rr = mid + 1, p = l;
while (ll <= mid && rr <= r)
if (Y[id[ll]] <= Y[id[rr]])
ary[p++] = id[ll++];
else ary[p++] = id[rr++];
while (rr <= r) ary[p++] = id[rr++];
while (ll <= mid) ary[p++] = id[ll++];
for (int i = l; i <= r; i++) id[i] = ary[i];
}
void mergeResort(int l, int r) {
int mid = (l + r) >> 1;
int ll = l, rr = mid + 1;
for (int i = l; i <= r; i++)
if (id[i] <= mid)
ary[ll++] = id[i];
else ary[rr++] = id[i];
for (int i = l; i <= r; i++) id[i] = ary[i];
}
struct Que {
int head, tail, val[N];
inline void clear() { head = tail = 0; }
inline int size() { return tail - head; }
inline void push(int a) { val[tail++] = a; }
inline void popBack() { tail--; }
inline void popFront() { head++; }
} Q;
inline DB calcK(int a, int b) {
if (Y[a] == Y[b]) return INF;
return (X[a] - X[b]) / (Y[a] - Y[b]);
}
inline bool judge(int a, int b, int c) {
// if (Y[a] == Y[b] || Y[b] == Y[c]) return false;
return calcK(a, b) > calcK(b, c) + EPS;
}
void figure(int l, int r) {
if (l == r) {
dp[l] = max(dp[l], dp[l - 1]);
X[l] = R[l] / (R[l] * A[l] + B[l]) * dp[l];
Y[l] = 1.0 / (R[l] * A[l] + B[l]) * dp[l];
return;
}
int mid = (l + r) >> 1;
mergeResort(l, r), figure(l, mid);
for (int i = l; i <= mid; i++) {
int now = id[i];
while (Q.size() >= 2 && !judge(Q.val[Q.tail - 2], Q.val[Q.tail - 1], now))
Q.popBack();
Q.push(now);
}
for (int i = mid + 1; i <= r; i++) {
int now = id[i];
while (Q.size() >= 2 && calcK(Q.val[Q.head], Q.val[Q.head + 1]) >= (-B[now] / A[now]))
Q.popFront();
int tmp = Q.val[Q.head];
dp[now] = max(dp[now], X[tmp] * A[now] + Y[tmp] * B[now]);
}
Q.clear(), figure(mid + 1, r), mergeSort(l, r);
}
int main() {
init();
figure(1, n);
printf("%.3lf\n", dp[n]);
return 0;
}
以上