[BZOJ1492][NOI2007]货币兑换Cash && CDQ分治+斜率优化
2015-04-09 20:16
489 查看
这种分治思想我也是醉了Orz
首先对于这道题 我们可以发现 如果某一天你要买进或卖出 那一定是尽可能的买或卖
那么我们就可以用一个状态f[i]表示某一天的最大收益
那么就有 f[i] = (rate[j] * f[j] * a[i] + f[j] * b[i]) / (rate[i] * a[i] + b[i]
那么朴素转移就很容易了 怎样优化呢
令
y[j] = f[j] / (rate[i] * a[i] + b[i])
x[j] = rate[j] * f[j] / (rate[i] * a[i] + b[i]) = rate[j] * y[j];
则有 f[i] = a[i] * x[j] + b[i] * y[j];
假设决策点j 优于 决策点k 并且 j < k 当且仅当
(y[k] - y[j]) / (x[k] - x[j]) < -a[i] / b[i]
我们可以将所有 -a[i] / b[i] 从大到小排序 那么就维护一个斜率单调递减的凸包
然后就是CDQ分治了 步骤如下
1. 把区间分成两段 得到mid
2. 在原序列中小于mid的部分 进行递归
3. 当L == R 时返回答案
4. 得到答案后 维护刚刚求解部分加入后的凸包 并用他们更新mid+1到R部分的f值
5. 递归处理右子区间
话虽这么说我还是感觉很难啊QAQ
首先对于这道题 我们可以发现 如果某一天你要买进或卖出 那一定是尽可能的买或卖
那么我们就可以用一个状态f[i]表示某一天的最大收益
那么就有 f[i] = (rate[j] * f[j] * a[i] + f[j] * b[i]) / (rate[i] * a[i] + b[i]
那么朴素转移就很容易了 怎样优化呢
令
y[j] = f[j] / (rate[i] * a[i] + b[i])
x[j] = rate[j] * f[j] / (rate[i] * a[i] + b[i]) = rate[j] * y[j];
则有 f[i] = a[i] * x[j] + b[i] * y[j];
假设决策点j 优于 决策点k 并且 j < k 当且仅当
(y[k] - y[j]) / (x[k] - x[j]) < -a[i] / b[i]
我们可以将所有 -a[i] / b[i] 从大到小排序 那么就维护一个斜率单调递减的凸包
然后就是CDQ分治了 步骤如下
1. 把区间分成两段 得到mid
2. 在原序列中小于mid的部分 进行递归
3. 当L == R 时返回答案
4. 得到答案后 维护刚刚求解部分加入后的凸包 并用他们更新mid+1到R部分的f值
5. 递归处理右子区间
话虽这么说我还是感觉很难啊QAQ
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<queue> #include<cmath> #define SF scanf #define PF printf using namespace std; typedef long long LL; const double eps = 1e-9; const double INF = 1e20; const int MAXN = 100000; int n, sta[MAXN+10], top, S; double f[MAXN+10]; struct Node { double x, y, a, b, rate, k; int id; bool operator < (const Node &t) const { return k > t.k; } } A[MAXN+10], tmp[MAXN+10]; double slope(int i, int j) { if(!j) return -INF; if(fabs(A[i].x - A[j].x) < eps) return INF; return (A[j].y - A[i].y) / (A[j].x - A[i].x); } void CDQ(int L, int R) { if(L == R) { f[L] = max(f[L], f[L-1]); A[L].y = f[L] / (A[L].a * A[L].rate + A[L].b); A[L].x = A[L].rate * A[L].y; return ; } int mid = (L + R) >> 1, l1 = L, l2 = mid+1; for(int i = L; i <= R; i++) { if(A[i].id <= mid) tmp[l1++] = A[i]; else tmp[l2++] = A[i]; } for(int i = L; i <= R; i++) A[i] = tmp[i]; CDQ(L, mid); top = 0; for(int i = L; i <= mid; i++) { while(top > 1 && slope(sta[top-1], sta[top]) < slope(sta[top-1], i) + eps) top--; sta[++top] = i; } sta[++top] = 0; int j = 1; for(int i = mid+1; i <= R; i++) { while(j < top && slope(sta[j], sta[j+1]) + eps > A[i].k) j++; f[A[i].id] = max(f[A[i].id], A[sta[j]].x * A[i].a + A[sta[j]].y * A[i].b); } CDQ(mid+1, R); l1 = L; l2 = mid+1; for(int i = L; i <= R; i++) { if(l1 <= mid && (l2 > R || A[l1].x < A[l2].x || (fabs(A[l1].x - A[l2].x) < eps && A[l1].y < A[l2].y))) tmp[i] = A[l1++]; else tmp[i] = A[l2++]; } for(int i = L; i <= R; i++) A[i] = tmp[i]; } int main() { SF("%d%d", &n, &S); f[0] = S; for(int i = 1; i <= n; i++) { SF("%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+1+n); CDQ(1, n); PF("%.3f", f ); return 0; }
相关文章推荐
- 【BZOJ1492】[NOI2007]货币兑换Cash 斜率优化+cdq分治
- BZOJ_1492_[NOI2007]货币兑换Cash_CDQ分治+斜率优化
- [bzoj1492][cdq分治][斜率优化][NOI2007]货币兑换Cash
- [BZOJ1492][NOI2007][CDQ分治][斜率优化][DP]货币兑换Cash
- [DP 斜率优化 CDQ分治||动态维护凸包] BZOJ 1492 [NOI2007]货币兑换Cash
- [BZOJ1492][NOI2007]货币兑换Cash(斜率优化dp+splay|cdq分治维护凸包)
- [BZOJ 1492][NOI2007]货币兑换Cash:CDQ分治|DP斜率优化
- BZOJ 1492: [NOI2007]货币兑换Cash [CDQ分治 斜率优化DP]
- [BZOJ1492][NOI2007][斜率优化][动态凸包][DP][分治]货币兑换cash
- BZOJ 1492 货币兑换Cash(CDQ分治+斜率优化dp)
- 斜率优化(CDQ分治,Splay平衡树):BZOJ 1492: [NOI2007]货币兑换Cash
- [BZOJ1492]-[NOI2007]货币兑换Cash-斜率优化+CDQ
- 【bzoj1492】【NOI2007】【货币兑换】【斜率优化+cdq分治】
- BZOJ1492:[NOI2007]货币兑换Cash (CDQ分治+斜率优化DP/平衡树维护凸壳)
- bzoj [NOI2007]货币兑换Cash (cdq分治+斜率优化 )
- NOI 2007 货币兑换Cash (bzoj 1492) - 斜率优化 - 动态规划 - CDQ分治
- BZOJ_P1492 [NOI2007]货币兑换Cash(CDQ分治+斜率优化)
- BZOJ1492:[NOI2007]货币兑换 (CDQ分治+斜率优化DP | splay动态维护凸包)
- bzoj1492 [NOI2007]货币兑换Cash【cdq分治】
- [BZOJ1492][NOI2007]货币兑换Cash(斜率优化+CDQ分治)