【問題描述】
??小 Y最近在一家金券交易所工作。該金券交易所只發行交易兩種金券:A紀念券(以下簡稱A券)和B紀念券(以下簡稱B券)。每個持有金券的顧客都有一個自己的 帳戶。金券的數目可以是一個實數。每天隨著市場的起伏波動,兩種金券都有自己當時的價值,即每一單位金券當天可以兌換的人民幣數目。我們記錄第K天中A券 和B券的價值分別為AK和BK(元/單位金券)。
為了方便顧客,金券交易所提供了一種非常方便的交易方式:比例交易法。
比例交易法分為兩個方面:
a)賣出金券:顧客提供一個[0,100]內的實數OP作為賣出比例,其意義為:將OP%的A券和OP%的B券以當時的價值兌換為人民幣;
b)買入金券:顧客支付IP元人民幣,交易所將會兌換給用戶總價值為IP的金券,并且,滿足提供給顧客的A券和B券的比例在第K天恰好為RateK;
例如,假定接下來3天內的Ak、Bk、RateK的變化分別為:
時間 | Ak | Bk | Ratek |
第一天 | 1 | 1 | 1 |
第二天 | 1 | 2 | 2 |
第三天 | 2 | 2 | 3 |
假定在第一天時,用戶手中有100元人民幣但是沒有任何金券。
用戶可以執行以下的操作:
時間 | 用戶操作 | 人民幣(元) | A券的數量 | B券的數量 |
開戶 | 無 | 100 | 0 | 0 |
第一天 | 買入100元 | 0 | 50 | 50 |
第二天 | 賣出50% | 75 | 25 | 25 |
第二天 | 買入60元 | 15 | 55 | 40 |
第三天 | 賣出100% | 205 | 0 | 0 |
注意到,同一天內可以進行多次操作。
小Y是一個很有經濟頭腦的員工,通過較長時間的運作和行情測算,他已經知道了未來N天內的A券和B券的價值以及Rate。他還希望能夠計算出來,如果開始時擁有S元錢,那么N天后最多能夠獲得多少元錢。
【輸入格式】
第一行兩個正整數N、S,分別表示小Y能預知的天數以及初始時擁有的錢數。接下來N行,第K行三個實數AK、BK、RateK,意義如題目中所述。
【輸出格式】
只有一個實數MaxProfit,表示第N天的操作結束時能夠獲得的最大的金錢數目。答案保留3位小數。
-----------------------------------------------------------
正解=動歸+平衡樹
考慮簡單Dp
? 狀態:設f[i]為第i天能賺的最多錢為多少
方程:f[i]=max(f[i-1],na*A+nb*B)(j< i)
(na,nb為第j天能換到的A劵數量和B劵數量)
考慮優化:
設 na 為 x,nb 為 y
則sum=x*A+y*B 既?y = -A/B*x+sum/B
由于A,B為定值
sum的Max以 -A/B 為斜率的過點(x,y)的截距的Max*B
顯然可能得到Max解截距的點必然是個上凸殼
建立以x為關鍵字的平衡樹維護值(其實很簡(dan)單(teng))
? ? ? 由于在樹上的點映射的截距具有單調性,
找最大值是便可通過平衡樹的前驅后繼判斷Max在左子樹或右子樹;
代碼如下:

1 #include<cstring> 2 #include<algorithm> 3 #include<cstdio> 4 #include< string > 5 #include<iostream> 6 #include<queue> 7 #define INF 99999999 8 #define LL long long 9 #define Cint(o) const int o=0 10 #define Cdou(o) const double o=0 11 #define Min(num1,num2) if(num1>num2) num1=num2 12 #define Max(num1,num2) if(num1<num2) num1=num2 13 struct Tree{ 14 int l,r,f; 15 double x,y; 16 Tree(Cint(a1),Cint(a2),Cint(a3),Cdou(a4),Cdou(a5)): 17 l(a1),r(a2),f(a3),x(a4),y(a5){} 18 }a[ 100010 ]; 19 int Root,Total,n; 20 const long double O=1e- 8 ; 21 void cal( double sum, double A, double B, double K, double &na, double & nb){ 22 nb=sum/(A*K+ B); 23 na=nb* K; 24 } 25 void rig( int now){ 26 int f= a[now].f; 27 a[now].f= a[f].f; 28 if (a[a[f].f].l==f) a[a[f].f].l= now; 29 if (a[a[f].f].r==f) a[a[f].f].r= now; 30 a[f].f= now; 31 a[f].l= a[now].r; 32 a[a[now].r].f= f; 33 a[now].r= f; 34 } 35 36 void lef( int now){ 37 int f= a[now].f; 38 a[now].f= a[f].f; 39 if (a[a[f].f].l==f) a[a[f].f].l= now; 40 if (a[a[f].f].r==f) a[a[f].f].r= now; 41 a[f].f= now; 42 a[f].r= a[now].l; 43 a[a[now].l].f= f; 44 a[now].l= f; 45 } 46 double cross(Tree A,Tree B,Tree C){ 47 return (B.x-A.x)*(C.y-A.y)-(C.x-A.x)*(B.y- A.y); 48 // x1 *y2-x2*y1 49 } 50 void splay( int now, int F= 0 ){ 51 while (a[now].f!= F){ 52 int f=a[now].f,ff= a[f].f; 53 if (ff== F) 54 if (a[f].l== now) rig(now); 55 else lef(now); 56 else 57 if (a[ff].l== f) 58 if (a[f].l== now) rig(f),rig(now); 59 else lef(now),rig(now); 60 else 61 if (a[f].l== now) rig(now),lef(now); 62 else lef(f),lef(now); 63 } 64 if (!F) Root= now; 65 } 66 67 void creat(){ 68 Total= 2 ; 69 Root= 1 ; 70 a[ 1 ].r= 2 ; 71 a[ 2 ].f= 1 ; 72 a[ 1 ].x=- INF; 73 a[ 2 ].x= INF; 74 } 75 int prev( int now){ 76 splay(now); 77 now= a[now].l; 78 while (a[now].r) now= a[now].r; 79 return now; 80 } 81 int succ( int now){ 82 splay(now); 83 now= a[now].r; 84 while (a[now].l) now= a[now].l; 85 return now; 86 } 87 void del( int start, int now, int end){ 88 splay(start); 89 splay(end,start); 90 a[a[Root].r].l= 0 ; 91 // printf("Delte(%d)",now); 92 } 93 void maintain( int now){ 94 int p=prev(now),s= succ(now); 95 if (p!= 1 &&s!= 2 ) 96 if (cross(a[p],a[s],a[now])< O){ 97 del(p,now,s); 98 return ; 99 } 100 while ( 1 ){ 101 if (p== 1 ) break ; 102 int pp= prev(p); 103 if (pp!= 1 &&cross(a[pp],a[now],a[p])< O) 104 del(pp,p,now), 105 p= pp; 106 else 107 break ; 108 } 109 while ( 1 ){ 110 if (s== 2 ) break ; 111 int ss= succ(s); 112 if (ss!= 2 &&cross(a[now],a[ss],a[s])< O) 113 del(now,s,ss), 114 s= ss; 115 else 116 break ; 117 } 118 } 119 void insert( double x, double y){ 120 for ( int now= Root;;){ 121 if (a[now].x-x<O&&x-a[now].x< O){ 122 Max(a[now].y,y); 123 maintain(now); 124 return ; 125 } 126 if (a[now].x-x> O) 127 if (a[now].l) 128 now= a[now].l; 129 else { 130 a[now].l=++ Total; 131 a[Total].f= now; 132 a[Total].x= x; 133 a[Total].y= y; 134 maintain(Total); 135 return ; 136 } 137 else 138 if (a[now].r) 139 now= a[now].r; 140 else { 141 a[now].r=++ Total; 142 a[Total].f= now; 143 a[Total].x= x; 144 a[Total].y= y; 145 maintain(Total); 146 return ; 147 148 } 149 } 150 } 151 double fo(Tree now, double K){ 152 return now.y-now.x* K; 153 } 154 int pre( int now){ 155 // splay(now); 156 now= a[now].l; 157 while (a[now].r) now= a[now].r; 158 return now; 159 } 160 161 int suc( int now){ 162 // splay(now); 163 now= a[now].r; 164 while (a[now].l) now= a[now].l; 165 return now; 166 } 167 double slove( double K){ 168 for ( int now= Root;;){ 169 if (now== 1 ){ 170 now= suc(now); 171 continue ; 172 } 173 if (now== 2 ){ 174 now= pre(now); 175 continue ; 176 } 177 178 if (a[now].l){ 179 int k= pre(now); 180 if (k!= 1 &&fo(a[now],K)<fo(a[k],K)+ O){ 181 now= a[now].l; 182 continue ; 183 } 184 } 185 if (a[now].r){ 186 int k= suc(now); 187 if (k!= 2 &&fo(a[now],K)<fo(a[k],K)+ O){ 188 now= a[now].r; 189 continue ; 190 } 191 } 192 return fo(a[now],K); 193 194 } 195 } 196 int main(){ 197 double A,B,K,na,nb,s; 198 scanf( " %d%lf " ,&n,& s); 199 scanf( " %lf%lf%lf " ,&A,&B,& K); 200 creat(); 201 cal(s,A,B,K,na,nb); 202 insert(na,nb); 203 for ( int i= 1 ;i<n;i++ ){ 204 scanf( " %lf%lf%lf " ,&A,&B,& K); 205 double temp=slove(-A/B)* B; 206 Max(s,temp); 207 cal(s,A,B,K,na,nb); 208 insert(na,nb); 209 } 210 printf( " %.3lf " ,s); 211 }
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
