[NOI2007]货币兑换Cash(DP+动态凸包)

第一次打动态凸包维护dp,感觉学到了超级多的东西。

首先,set是如此的好用!!!可以通过控制一个flag来实现两种查询,维护凸包和查找斜率k

不过就是重载运算符和一些细节方面有些恶心,90行解决

后面还有一个cdq分治,找时间学下,看下能不能处理一大类恶心的问题

github还是不会用,找时间搞下吧

CODE:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<set>
 6 #include<cmath>
 7 using namespace std;
 8 const double esp=1e-7;
 9 const int maxn=101000;
10 int dcmp(double a) {
11     if (fabs(a)<esp) return 0;
12     return a<0?-1:1;
13 }
14 struct node{
15     double x,y,k;bool f;
16     node(double _x,double _y):x(_x),y(_y),f(0){}
17     node():f(0){}
18     inline bool error(){return x>1e50;}
19 }error(1e51,0);
20 inline bool operator == (const node x,const node y) {return dcmp(x.x-y.x)==0;}
21 inline bool operator < (const node x,const node y){
22     if (x.f||y.f) return dcmp(x.k-y.k)>0;
23     else return dcmp(x.x-y.x)<0;
24 }
25 inline double operator *(const node x,const node y) {return x.x*y.y-x.y*y.x;}
26 inline node operator -(const node x,const node y){
27     node tmp;
28     tmp.x=x.x-y.x;tmp.y=x.y-y.y;
29     return tmp;
30 }
31 inline double calc_k(node x,node y) {return (x.y-y.y)/(x.x-y.x);}
32 set<node> gap;
33 typedef set<node>::iterator iter;
34 inline node lower(node x) {
35    iter it=gap.lower_bound(x);
36    return it==gap.end()?error:*it;
37 }
38 inline node next(node x) {
39     iter it=gap.upper_bound(x);
40     return it==gap.end()?error:*it;
41 }
42 inline node pre(node x) {
43     iter it=gap.lower_bound(x);
44     return it==gap.begin()?error:*(--it);
45 }
46 inline void ins(node a) {
47     if (gap.empty()) {a.k=0;gap.insert(a);return;}
48     node d1=pre(a),d2=lower(a);
49     if (d1.error()&&d2.y>a.y) return ;
50     if ((!d1.error())&&(!d2.error())&&(dcmp((d2-d1)*(a-d1))<=0)) return ;
51     if (d2==a) return;
52     node p1,p2=next(a);
53     for (;;){
54         p1=p2;p2=next(p2);
55         if (p1.error()||p2.error()) break;
56         if (dcmp((p1-a)*(p2-a))<=0) break;
57         gap.erase(p1);
58     }
59     p2=pre(a);
60     for (;;){
61         p1=p2;p2=pre(p2);
62         if (p1.error()||p2.error()) break;
63         if (dcmp((p1-a)*(p2-a))>=0) break;
64         gap.erase(p1);
65     }
66     d1=pre(a),d2=next(a);
67     if (d1.error()) a.k=0;else a.k=calc_k(d1,a);gap.insert(a);
68     if (!d2.error()) gap.erase(d2),d2.k=calc_k(a,d2),gap.insert(d2);
69 }
70 inline double get_k(double a,double b) {
71     node tmp;tmp.f=1;tmp.k=-a/b;
72     tmp=*(--gap.lower_bound(tmp));
73     return a*tmp.x+b*tmp.y;
74 }
75 double a[maxn],b[maxn],r[maxn],na[maxn],nb[maxn],f[maxn];
76 int main(){
77     int n,s;
78     scanf("%d%d",&n,&s);
79     for (int i=1;i<=n;i++) scanf("%lf%lf%lf",a+i,b+i,r+i);
80     f[1]=s;
81     nb[1]=f[1]/(a[1]*r[1]+b[1]);
82     na[1]=nb[1]*r[1];
83     ins(node(na[1],nb[1]));
84     for (int i=2;i<=n;i++) {
85         f[i]=max(f[i-1],get_k(a[i],b[i]));
86         nb[i]=f[i]/(a[i]*r[i]+b[i]);
87         na[i]=nb[i]*r[i];
88         ins(node(na[i],nb[i]));
89     }
90     printf("%.3f\n",f[n]);
91 }
92     

  

时间: 2024-12-19 05:41:06

[NOI2007]货币兑换Cash(DP+动态凸包)的相关文章

BZOJ 1492: [NOI2007]货币兑换Cash( dp + 平衡树 )

dp(i) = max(dp(i-1), x[j]*a[i]+y[j]*b[i]), 0<j<i. x, y表示某天拥有的最多钱去买金券, 金券a和金券b的数量. 然后就很明显了...平衡树维护上凸壳, 询问时就在凸壳上二分...时间复杂度O(NlogN) ----------------------------------------------------------------------------------------------- #include<cmath> #i

bzoj1492[NOI2007]货币兑换Cash cdq分治+斜率优化dp

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5541  Solved: 2228[Submit][Status][Discuss] Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金

[BZOJ1492] [NOI2007]货币兑换Cash 斜率优化+cdq/平衡树维护凸包

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5907  Solved: 2377[Submit][Status][Discuss] Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金

bzoj [NOI2007]货币兑换Cash (cdq分治+斜率优化 )

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 2454  Solved: 1078 [Submit][Status][Discuss] Description Input 第一行两个正整数N.S,分别表示小Y 能预知的天数以及初始时拥有的钱数. 接下来N 行,第K 行三个实数AK.BK.RateK,意义如题目中所述 Output 只有一个实数MaxProfit,表示第N 天的操作结束时能够获得的最大的

【BZOJ-1492】货币兑换Cash DP + 斜率优化 + CDQ分治

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 3396  Solved: 1434[Submit][Status][Discuss] Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金

【BZOJ1492】[NOI2007]货币兑换Cash 斜率优化+cdq分治

[BZOJ10492][NOI2007]货币兑换Cash Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动,两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目.我们记录第 K 天中 A券 和 B券 的价值分别为 AK 和 BK(元/单位金券).为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易

【BZOJ 1492】 [NOI2007]货币兑换Cash

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1948  Solved: 879 [Submit][Status][Discuss] Description Input 第一行两个正整数N.S,分别表示小Y 能预知的天数以及初始时拥有的钱数. 接下来N 行,第K 行三个实数AK.BK.RateK,意义如题目中所述 Output 只有一个实数MaxProfit,表示第N 天的操作结束时能够获得的最大的金

bzoj千题计划237:bzoj1492: [NOI2007]货币兑换Cash

http://www.lydsy.com/JudgeOnline/problem.php?id=1492 dp[i] 表示 第i天卖完的最大收益 朴素的dp: 枚举从哪一天买来的在第i天卖掉,或者是不操作 dp[i]=max(dp[i-1],X[j]*A[i]+Y[j]*B[i]) 其中X[j]表示在第j天能买多少A纪念券,Y[j]表示在第j天能买多少B纪念券 可列方程 X[j]*A[j]+Y[j]*B[j]=dp[j] 又因为 X[j]=Rate[j]*Y[j] 所以解出 Y[j]=dp[j]

[BZOJ1492][NOI2007]货币兑换Cash(斜率优化+CDQ分治)

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5838  Solved: 2345[Submit][Status][Discuss] Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金