【bzoj1492】[NOI2007]货币兑换Cash

来源:互联网 发布:淘宝金牌客服沟通技巧 编辑:程序博客网 时间:2024/04/29 21:41

此题非常的经典(似乎cdq分治就是从这题引出的)

基础思想就是cdq分治优化dp。

网上题解似乎很多。。

所以dp什么的就不写了。

重点就是通过cdq来满足斜率优化的条件(维护凸包)

#include <bits/stdc++.h>#define gc getchar()#define N 100009#define mid (l+r>>1)#define eps 1e-7#define inf 1e10using namespace std;int n,s,sta[N];double dp[N];struct node{double k,a,b,r;int pos;bool operator <(const node &rhs) const{return k<rhs.k;}}q[N],now[N];struct point{double x,y;bool operator <(const point &rhs) const{return x<rhs.x||(fabs(x-rhs.x)<eps&&y<rhs.y);}}p[N],Now[N];double get_k(int a,int b){if (a==0||b==0) return -inf;if (fabs(p[a].x-p[b].x)<eps) return -inf;return (p[a].y-p[b].y)/(p[a].x-p[b].x);}void solve(int l,int r){if (l==r){dp[l]=max(dp[l-1],dp[l]);p[l].y=dp[l]/(q[l].a*q[l].r+q[l].b);p[l].x=p[l].y*q[l].r;return;}int l1=l,l2=mid+1;for (int i=l;i<=r;i++)if (q[i].pos<=mid) now[l1++]=q[i];else now[l2++]=q[i];for (int i=l;i<=r;i++) q[i]=now[i];solve(l,mid);int top=0;for (int i=l;i<=mid;i++)//k dijian{while (top>=2&&get_k(i,sta[top])>get_k(sta[top],sta[top-1])) top--;sta[++top]=i;}int j=1;for (int i=r;i>mid;i--)//k dijian{while (j<top&&q[i].k<get_k(sta[j],sta[j+1])) j++;dp[q[i].pos]=max(dp[q[i].pos],q[i].a*p[sta[j]].x+q[i].b*p[sta[j]].y);}solve(mid+1,r);l1=l,l2=mid+1;for (int i=l;i<=r;i++)if ((p[l1]<p[l2]||l2>r)&&l1<=mid) Now[i]=p[l1++];else Now[i]=p[l2++];for (int i=l;i<=r;i++)p[i]=Now[i];}int main(){scanf("%d%lf",&n,&dp[0]);for (int i=1;i<=n;i++){scanf("%lf%lf%lf",&q[i].a,&q[i].b,&q[i].r);q[i].k=-q[i].a/q[i].b,q[i].pos=i;}sort(q+1,q+n+1);solve(1,n);printf("%.3lf\n",dp[n]);return 0;}


原创粉丝点击