标签:
cdq分治,dp。这道题太难了,我看了一上午一点头绪也没有//蒟蒻本性
连这篇题解都是边做边写的,要不就忘了(雾)。。
维护的是上凸包。
2.30 pm 终于过了,照着人家的题解打,居然都交了10多遍。//蒟蒻本性
首先,不难得到这样的结论:如果买就要把所有的钱都用完(买能挣钱,就要多买,不如其他的挣钱就买别的)。如果卖,就要都卖掉。
用数组a保存a[i],b[i],rate[i]。
用f[i].x代表第x天能买到最多的a物品,f[i].y代表最多的b物品。则有f[i].x = f[i].y*a[i].r。
用v[i]代表第i天能得到最大的收益,则有v[i] = max(v[i]-1,f[i].x*a[i]+f[i].y*b[i])。
暴力枚举O(n^2),tle。
所以需要维护一个上凸包。
在第i天时,假设f[j].x<=f[k].x,如果决策j优于k,则有 (f[i].x-f[j].x)*a[i].a+(f[j].y-f[k].y)*a[i].b>0。
经过移项,就有 (f[j].y-f[j].y)/(f[j].x-f[j].x) < –a[i].a/a[i].b。
先记住这个结论,那么利用呢?
1.在预处理时先按(-a[i]/b[i])降序排序。
2/然后依靠平衡树(我不会。。)和cdq分治(我抄的。。)了。
cdq分治:首先先把要处理的区间分成俩部分,先递归处理左区间,然后计算右区间,最后递归处理右区间。
这样有什么好处呢? 就是在计算一天的dp值的时候,也处理了后面所有天数的dp值的一部分。
为什么呢?如果我们按单调性排序了以后,维护出一个下凸包。
在处理第j天时,假设第k天为决策最优,这样k天以前的值在第j天以后的决策中都没用了。
因为满足 小于 –a[j].a/a[j].b,必定小于–a[h].a/a[h].b,h>j。因为排序过了。
分治一共logn层,每层遍历n个数,总复杂度O(nlogn)。
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int maxn = 100000 + 10; int n,m,p[maxn],s[maxn]; struct Point { double x,y; }f[maxn],t[maxn]; struct DAY { double a,b,r; } a[maxn]; double v[maxn]; bool operator < (Point a,Point b) { return a.x < b.x || (a.x==b.x&&a.y<b.y); } bool cmp(int x,int y) { return a[x].b/a[x].a > a[y].b/a[y].a; } bool dir(Point a,Point b,Point c) { return ((b.x-a.x)*(c.y-b.y)-(b.y-a.y)*(c.x-b.x))>=0; } double calc(Point f,int i) { return f.x*a[i].a + f.y*a[i].b; } void cdq(int l,int r,double m) { if(l == r) { v[l] = max(v[l],m); f[l].y = v[l]/(a[l].a*a[l].r+a[l].b); f[l].x = a[l].r*f[l].y; return; } int mid = (l+r)/2,m1=l,m2=mid+1,L=0,R=0; for(int i=l;i<=r;i++) { if(p[i]<=mid) s[m1++]=p[i]; else s[m2++]=p[i]; } memcpy(p+l,s+l,sizeof(int)*(r-l+1)); cdq(l,mid,m); for(int i=l;i<=mid;i++) { while(R>1 && dir(t[R-2],t[R-1],f[i])) R--; t[R++] = f[i]; } for(int i=mid+1;i<=r;i++) { while(L<R-1 && calc(t[L],p[i])<calc(t[L+1],p[i])) ++L; v[p[i]] = max(v[p[i]],calc(t[L],p[i])); } cdq(mid+1,r,v[mid]); merge(f+l,f+mid+1,f+mid+1,f+r+1,t); memcpy(f+l,t,sizeof(Point)*(r-l+1)); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%lf%lf%lf",&a[i].a,&a[i].b,&a[i].r); p[i] = i; } sort(p+1,p+n+1,cmp); cdq(1,n,m); printf("%.3lf\n",v[n]); return 0; }
标签:
原文地址:http://www.cnblogs.com/invoid/p/5398401.html