1. 程式人生 > >【BZOJ1492】【NOI2007】貨幣兌換

【BZOJ1492】【NOI2007】貨幣兌換

view .cn one src ostream 不清楚 span splay 方案

我果然不會斜率優化

原題:

小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 的變化分別為: 技術分享
假定在第一天時,用戶手中有 100元 人民幣但是沒有任何金券。用戶可以執行以下的操作: 技術分享 註意到,同一天內可以進行多次操作。小Y是一個很有經濟頭腦的員工,通過較長時間的運作和行情測算,他已經 知道了未來N天內的A券和B券的價值以及Rate。他還希望能夠計算出來,如果開始時擁有S元錢,那麽N天後最多能 夠獲得多少元錢。 2.必然存在一種最優的買賣方案滿足: 每次買進操作使用完所有的人民幣; 每次賣出操作賣出所有的金券。 n<=100000 神題QAQ cdq太神了QAQ 恩首先需要想到一個思路非常鬼畜的基礎dp: 令f[i]為第i天把錢花光最多能持有多少A券,則技術分享

f[i]這麽鬼畜的意義我是想不到啊QAQ

恩這道題從一開始就鬼畜了起來

根據得出的基礎dp可以寫出n^2的程序,顯然優化對吧,斜率優化(為啥要斜率優化?我不懂啊QAQ

然後令j比k優,就醬技術分享

令g[i]=f[i]/rate[i],醬技術分享

然後就斜率優化了,但是維護凸包似乎很麻煩(我不會QAQ),splay不好寫,我們cdq分治

具體咋整,看代碼意會吧我講不清楚QAQ

方便以後常看所以代碼加了註釋QAQ

代碼:(抄黃學長的QAQ

技術分享
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5
#include<cmath> 6 using namespace std; 7 const double inf=1e20; 8 const double eps=2e-9; 9 struct nds{double x,y,a,b,k,rt; int w,id;}a[110000],tmp[110000]; 10 int n; 11 double f[110000]; 12 int stck[110000],tp=0; 13 double gtk(int x,int y){ 14 if(!y) return -inf; 15 if(fabs(a[x].x-a[y].x)<eps) return inf; 16 return (a[y].y-a[x].y)/(a[y].x-a[x].x); 17 } 18 void cdq(int l,int r){ 19 if(l==r){ 20 f[l]=max(f[l],f[l-1]); 21 a[l].y=f[l]/(a[l].a*a[l].rt+a[l].b);//y是a券的個數 22 a[l].x=a[l].rt*a[l].y;//x是b券 23 return ; 24 } 25 int md=(l+r)>>1; int t1=l,t2=md+1; 26 for(int i=l;i<=r;++i) tmp[(a[i].id<=md?t1:t2)++]=a[i]; 27 for(int i=l;i<=r;++i) a[i]=tmp[i];//先按照原來id左右劃分 28 cdq(l,md);//中序cdq 29 tp=0; 30 for(int i=l;i<=md;++i){ 31 while(tp>1 && gtk(stck[tp-1],stck[tp])<gtk(stck[tp-1],i)+eps) --tp; stck[++tp]=i; 32 }//搞左邊的凸包 33 stck[++tp]=0; 34 for(int i=md+1,j=1;i<=r;++i){ 35 while(j<tp && gtk(stck[j],stck[j+1])+eps>a[i].k) ++j; 36 f[a[i].id]=max(f[a[i].id],a[stck[j]].x*a[i].a+a[stck[j]].y*a[i].b); 37 }//更新答案 38 cdq(md+1,r); 39 t1=l,t2=md+1; 40 for(int i=l;i<=r;++i){ 41 if(t1>md) tmp[i]=a[t2++]; 42 else if(t2>r) tmp[i]=a[t1++]; 43 else tmp[i]=a[(a[t1].x<a[t2].x||(fabs(a[t1].x-a[t2].x)<eps&&a[t1].y<a[t2].y)?t1:t2)++]; 44 }//按x第一y第二優先級排序,方便上一層搞凸包a 45 for(int i=l;i<=r;++i) a[i]=tmp[i]; 46 } 47 bool cmp(nds a,nds b){ return a.k>b.k;} 48 int main(){freopen("ddd.in","r",stdin); 49 scanf("%d%lf",&n,&f[0]); 50 for(int i=1;i<=n;++i){ 51 scanf("%lf%lf%lf",&a[i].a,&a[i].b,&a[i].rt); 52 a[i].k=-a[i].a/a[i].b,a[i].id=i; 53 } 54 sort(a+1,a+n+1,cmp);//沒想明白對k排序的意義QAQ 55 cdq(1,n); 56 printf("%.3lf\n",f[n]); 57 return 0; 58 }
View Code

【BZOJ1492】【NOI2007】貨幣兌換