laekov

BZOJ1492 [NOI2007]货币兑换Cash

cdq分治第二题。


最初没看清题所以一直不会做。晕。


cdq教程里的模板题。


显然所有卖都是卖完,买都是把钱买光。


f[i]表示第i天结束后最多持有b卷的数量,ans表示当前最多能赚到的rmb。


方程是:

f[i] = max(ans, f[j] * r[j] * a[i] + f[j] * b[i]) / (a[i] * r[i] + b[i])。


移项得:

f[j] = -(a[i]/b[i]) * (r[j] * f[j]) + (r[i] * a[i] + b[i]) / b[i] * f[j]。


把r[j]*f[j]看作x,把f[j]看作y,好像可以斜率优化了。


 不急,f[j]好像没有单调性吧?不对,好像a[i]/b[i]也没有单调性!?


平衡树维护凸壳?想起了上回那道hnoi的作业,调了一晚上,怎么能这样。


然后,其实可以cdq。


每次对右边有影响的是左边的凸壳,所以先跑左边,计算左边对右边的影响,再跑右边。这回是中序遍历,而不是Mokia那题的后序。


原来cdq可以这么神奇。


然后又把凸壳写丑了TT。


#include <cstdio>

#include <cstring>

#include <algorithm>


using namespace std;


const int maxn = 100009;


double ans, s, f[maxn], a[maxn], b[maxn], r[maxn];

int n, h[maxn], tmp[maxn], t;


inline double getx(const int& i) {

return f[i] * r[i];

}


inline double gety(const int& i) {

return f[i];

}


inline double getk(const int& i, const int& j) {

return (gety(j) - gety(i)) / (getx(j) - getx(i));

}


inline bool cmpP(const int& a, const int& b) {

return f[a] * r[a] < f[b] * r[b] || (f[a] * r[a] == f[b] * r[b] && f[a] < f[b]);

}


int getmax(int l, int r, double k) {

-- r;

if (l == r)

return h[l];

-- r;

if (k < getk(h[r], h[r + 1]))

return h[r + 1];

while (l < r) {

int mid = (l + r) >> 1;

if (k < getk(h[mid], h[mid + 1]))

l = mid + 1;

else

r = mid;

}

return h[l];

}


inline double mulx(const int& a, const int& b, const int& c, const int& d) {

double x1 = getx(b) - getx(a), y1 = gety(b) - gety(a);

double x2 = getx(d) - getx(c), y2 = gety(d) - gety(c);

return x1 * y2 - x2 * y1;

}


void cdq(int l, int r, int& tb, double& ans) {

if (l + 1 == r) {

double fn = 1.0 / (:: r[l] * a[l] + b[l]);

if (fn > f[l])

f[l] = fn;

h[(tb = r) - 1] = l;

ans = f[l] * (:: r[l] * a[l] + b[l]);

}

else {

int bl, br, mid = (l + r) >> 1;

double sl, sr;

cdq(l, mid, bl, sl);

ans = sl;

for (int i = mid; i < r; ++ i) {

int j = getmax(l, bl, -a[i] / b[i]);

double fn = max(sl, f[j] * (:: r[j] * a[i] + b[i])) / (:: r[i] * a[i] + b[i]);

if (fn > f[i]) {

f[i] = fn;

}

ans = max(ans, f[i] * (:: r[i] * a[i] + b[i]));

}

cdq(mid, r, br, sr);

ans = max(ans, sr);

tb = l;

for (int i = l, j = mid; i < bl || j < br;) {

int k;

if (j == br || (i < bl && getx(h[i]) < getx(h[j])))

k = h[i ++];

else

k = h[j ++];

while (tb > l + 1 && mulx(tmp[tb - 2], tmp[tb - 1], tmp[tb - 2], k) >= 0)

-- tb;

tmp[tb ++] = k;

}

for (int i = l; i < tb; ++ i)

h[i] = tmp[i];

}

}


int main() {

#ifndef ONLINE_JUDGE

freopen("in.txt", "r", stdin);

#endif


memset(f, 0, sizeof(f));

scanf("%d%lf", &n, &s);

for (int i = 0; i < n; ++ i)

scanf("%lf%lf%lf", a + i, b + i, r + i);

cdq(0, n, t, ans);

printf("%.3lf\n", ans * s);

}


评论

© laekov | Powered by LOFTER