bzoj1492 NOI2007 货币兑换Cash
题解:
题目都提示了,
很明显要导一波式子:
$$dp[i]=max( dp[i-1] , \frac{ dp[j] } { A[j]*R[j]+B[j] } * (A[i]*R[j]+B[i]))$$
后面那个东西相当与将第j天的R[j]个A和1个B绑在一起。
$dp[i-1]$没什么好说的,关键是后面那个。
看起来还可以提一下。
$$dp[i]=\frac{dp[j]}{A[j]*R[j]+B[j]}*(A[i]*R[j]+B[i])$$
把右面$A[i]$移项:
$$\frac{dp[i]}{A[i]}=\frac{dp[j]*R[j]}{A[j]*R[j]+B[j]}+\frac{B[i]}{A[i]}*\frac{dp[j]}{A[j]*R[j]+B[j]}$$
再移一下:
$$\frac{dp[j]*R[j]}{A[j]*R[j]+B[j]}=-\frac{B[i]}{A[i]}*\frac{dp[j]}{A[j]*R[j]+B[j]}+\frac{dp[i]}{A[i]}$$
现在让$b$项最大,维护斜率递减的上凸包。
但是x没有单调性啊……
于是就有两种处理方法。
第一种是$splay$在线强插,比较恶心;
第二种是$cdq$离线处理,非常好写。
由于我们要尽可能优化时间,可以考虑每次更新之前让左区间的$x$有序,右区间的$k$有序。
这样的话左边$O(n)$建凸包,右边$O(n)$匹配。
但是每次都要排序啊……
我们不妨先将整个区间关于$k$排序,然后分治前按编号分好,这样可以保证右边的k一定是单调的。
这样整体就是$O(nlogn)$了。
代码:
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define db double #define N 100050 const db eps = 1e-8; const db inf = 1e10; int n; db dp[N]; struct node { db a,b,r,x,y,k; int id; }p[N],tmp[N]; db slop(node n1,node n2) { if(fabs(n1.x-n2.x)<=eps)return inf; return (n1.y-n2.y)/(n1.x-n2.x); } bool cmpid(node n1,node n2) { return n1.id<n2.id; } bool cmpk(node n1,node n2) { return n1.k<n2.k; } void Sort(int l,int r)//cmp x { int mid = (l+r)>>1; int i=l,j = mid+1,k = l-1; while(i<=mid&&j<=r) { while(i<=mid&&p[i].x<=p[j].x)tmp[++k]=p[i++]; while(j<=r&&p[i].x>p[j].x)tmp[++k]=p[j++]; } while(i<=mid)tmp[++k]=p[i++]; while(j<=r)tmp[++k]=p[j++]; for(i=l;i<=r;i++)p[i]=tmp[i]; } void divi(int l,int r) { int mid = (l+r)>>1; int i=l-1,j=mid; for(int k=l;k<=r;k++) { if(p[k].id<=mid)tmp[++i]=p[k]; else tmp[++j]=p[k]; } for(int k=l;k<=r;k++)p[k]=tmp[k]; } int sta[N],tl; void cdq(int l,int r) { if(l==r) { dp[l] = max(dp[l],dp[l-1]); p[l].x = dp[l]/(p[l].a*p[l].r+p[l].b); p[l].y = p[l].x*p[l].r; return ; } int mid = (l+r)>>1; divi(l,r); cdq(l,mid); tl = 0; for(int i=l;i<=mid;i++) { while(tl>=2&&slop(p[sta[tl]],p[i])+eps>slop(p[sta[tl]],p[sta[tl-1]]))tl--; sta[++tl] = i; } for(int i=mid+1;i<=r;i++) { while(tl>=2&&slop(p[sta[tl]],p[sta[tl-1]])<p[i].k+eps)tl--; dp[p[i].id] = max(dp[p[i].id],p[sta[tl]].x*p[i].b+p[sta[tl]].y*p[i].a); } cdq(mid+1,r); Sort(l,r); } int main() { scanf("%d%lf",&n,&dp[0]); for(int i=1;i<=n;i++) { scanf("%lf%lf%lf",&p[i].a,&p[i].b,&p[i].r); p[i].k = -p[i].b/p[i].a;p[i].id = i; } sort(p+1,p+1+n,cmpk); cdq(1,n); printf("%.3lf\n",dp[n]); return 0; }