http://www.lydsy.com/JudgeOnline/problem.php?id=1492
這道題的關鍵在於 一天可以交易任意次和
必然存在一種最優的買賣方案滿足:
·每次買進操作使用完所有的人民幣;
·每次賣出操作賣出所有的金券。
這樣就可以用一維的DP求解了,設dp[i]表示前i天所得的最優解
由於只能按比例購買,所以可以把A和B組合成一種價格為K = (a[j]*r[j]+b[j])/(r[j]+1)的證券
則dp[i] = max(dp[j]/K*(r[j]/(r[j]+1))*a[i]+dp[j]/K*(1/(r[j]+1))*b[i])
化簡後 dp[i] = max(dp[j]/(a[j]*r[j]+b[j])*r[j]*a[i]+dp[j]/(a[j]r[j]+b[j])*b[i])
令X表示dp[j]/(a[j]*r[j]+b[j])*r[j],Y表示dp[j]/(a[j]r[j]+b[j])
G = X*a[i]+Y*b[i] => Y = -(a[i]/b[i])X+G/b[i]
但是X,Y,斜率全都不是單調的了,所以不能用單調隊列維護,但是其本質還是維護一個單調遞減的上凸殼,只是要從中間插入點並且維護,查詢要找到與直線相切的點。
插入點並且維護論文和網上都有很多詳細的說明了,這裡說一下查詢的問題
論文上說用二分,網上的很多題解也是在splay上進行二分找到相切點,我開始也這樣寫,但發現有倆個點過不了,然後一細想,這個不是單調函數,而是單峰函數,需要三分才行,然後就寫了一個splay上的三分,過了那倆個點,但效率劇慢,因為splay上的三分需要伸展多次,很耗時間,後來又想到了一種方法不用伸展的方法
beg 先判斷左右孩子的值,
如果發現有一個比根節點大,則移動到相應的孩子(因為函數是單峰的,所以倆個孩子中最多隻能有一個比根節點大),
跳轉beg
否則判斷該根節點的前驅和後繼的值,如果發現比根節點大的,移動到相應的孩子(前驅對應左孩子,後繼對應右孩子)
跳轉beg
如果還沒發現比根節點大就return,(這說明已經到達了函數的峰值)
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility> #include <map>#include <string> #include <climits> #include <set>#include <string> #include <sstream>#include <utility> #include <ctime>#include <bitset>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::stringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;using std::unique;using std::lower_bound;using std::random_shuffle;using std::bitset;using std::upper_bound;using std::multiset;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;typedef LL TY;typedef long double LF;const int MAXN(2000010);const int MAXM(101010);const int MAXE(100010);const int MAXK(6);const int HSIZE(31313);const int SIGMA_SIZE(26);const int MAXH(19);const int INFI((INT_MAX-1) >> 1);const ULL BASE(31);const LL LIM(10000000);const int INV(-10000);const int MOD(20100403);const double EPS(1e-6);const LF PI(acos(-1.0));template<typename T> void checkmax(T &a, T b){if(b > a) a = b;}template<typename T> void checkmin(T &a, T b){if(b < a) a = b;}template<typename T> T ABS(const T &a){return a < 0? -a: a;}double table[MAXN];double A[MAXN], B[MAXN], R[MAXN];struct SPLAY_TREE{struct NODE{double x, y;int size;NODE *fa, *ch[2];};NODE pool[MAXN];NODE *root, *NIL, *rear, *ll, *rl;inline void push_up(NODE *rt){rt->size = rt->ch[0]->size+rt->ch[1]->size+1;}void newnode(NODE *&rt, NODE *f, double x_, double y_){rt = rear++;rt->x = x_;rt->y = y_;rt->size = 1;rt->fa = f;rt->ch[0] = rt->ch[1] = NIL;}void init(){NIL = pool;NIL->ch[0] = NIL->ch[1] = NIL->fa = NIL;NIL->size = 0;rear = pool+1;newnode(root, NIL, -1e13, 1e6);newnode(root->ch[1], root, 1e6, -1e13);push_up(root->ch[1]);push_up(root);ll = root;rl = root->ch[1];}void rotate(NODE *rt, int flag){NODE *f = rt->fa;f->ch[!flag] = rt->ch[flag];rt->ch[flag]->fa = f;rt->fa = f->fa;if(f->fa != NIL) f->fa->ch[f->fa->ch[1] == f] = rt;rt->ch[flag] = f;f->fa = rt;push_up(f);}void splay(NODE *rt, NODE *goal){while(rt->fa != goal){if(rt->fa->fa == goal)rotate(rt, rt->fa->ch[0] == rt);else{NODE *f = rt->fa;int flag = (f->fa->ch[0] == f);if(f->ch[flag] == rt) rotate(rt, !flag);else rotate(f, flag);rotate(rt, flag);}}push_up(rt);if(goal == NIL) root = rt;}NODE *select(NODE *rt, int r){while(true){if(r == rt->ch[0]->size+1) break;if(r <= rt->ch[0]->size) rt = rt->ch[0];else {r -= rt->ch[0]->size+1;rt = rt->ch[1];}}return rt;}void insert(double x_, double y_){NODE *f = NIL, *rt = root;//插入(x_, y_)while(rt != NIL){f = rt;rt = rt->ch[rt->x < x_];}splay(f, NIL);if(f->x < x_){rt = select(root->ch[1], 1);splay(rt, root);}else{rt = select(root, root->ch[0]->size);splay(rt, NIL);splay(f, root);}newnode(root->ch[1]->ch[0], root->ch[1], x_, y_);push_up(root->ch[1]);push_up(root);splay(root->ch[1]->ch[0], NIL);//插入結束NODE *tp = root, *tp1, *tp2;//向左維護tp1 = select(root, root->ch[0]->size);splay(tp1, NIL);while(root->ch[0]->size >= 1){tp2 = select(root, root->ch[0]->size);splay(tp2, NIL);if((tp->y-tp1->y)*(tp->x-tp2->x) < (tp->y-tp2->y)*(tp->x-tp1->x)) break;tp1 = tp2;}splay(tp1, NIL);splay(tp, root);tp->ch[0] = NIL;push_up(root->ch[1]);push_up(root);//向右維護splay(tp, NIL);tp1 = select(root->ch[1], 1);splay(tp1, NIL);while(root->ch[1]->size >= 1){tp2 = select(root->ch[1], 1);splay(tp2, NIL);if((tp1->y-tp->y)*(tp2->x-tp->x) > (tp2->y-tp->y)*(tp1->x-tp->x)) break;tp1 = tp2;}splay(tp, NIL);splay(tp1, root);tp1->ch[0] = NIL;push_up(root->ch[1]);push_up(root);//看(x_, y_)是否在凸殼上splay(tp, NIL);tp1 = select(root, root->ch[0]->size);tp2 = select(root->ch[1], 1);if((tp->y-tp1->y)*(tp2->x-tp->x) <= (tp2->y-tp->y)*(tp->x-tp1->x)){splay(tp1, NIL);splay(tp2, root);tp2->ch[0] = NIL;push_up(root->ch[1]);push_up(root);}}double query(int ind){double ta = A[ind], tb = B[ind];NODE *tp, *f, *tp1, *tp2;double t, t1, t2, ret = 0;ret = root->x*ta+root->y*tb;tp = root;while(true){f = tp;t = tp->x*ta+tp->y*tb;t1 = tp->ch[0]->x*ta+tp->ch[0]->y*tb;t2 = tp->ch[1]->x*ta+tp->ch[1]->y*tb;if(t1 > t){checkmax(ret, t1);tp = tp->ch[0];continue;}if(t2 > t){checkmax(ret, t2);tp = tp->ch[1];continue;}if(tp->ch[0] != NIL){tp1 = select(tp, tp->ch[0]->size);t1 = tp1->x*ta+tp1->y*tb;if(t1 > t){tp = tp->ch[0];continue;}}if(tp->ch[1] != NIL){tp2 = select(tp->ch[1], 1);t1 = tp2->x*ta+tp2->y*tb;if(t1 > t){tp = tp->ch[1];continue;}}break;}/* 三分法splay(ll, NIL);splay(rl, root);double ret1;while(true) {tp = root->ch[1]->ch[0];if(tp->size == 1){checkmax(ret1, tp->x*ta+tp->y*tb);break;}if(tp->size == 0) break;if(tp->size == 2){tp1 = select(tp, 1);tp2 = select(tp, 2);}else{tp1 = select(tp, tp->size/3);tp2 = select(tp, tp->size/3*2);}t1 = tp1->x*ta+tp1->y*tb;t2 = tp2->x*ta+tp2->y*tb;if(t1 < t2){checkmax(ret1, t2);tp2 = root->ch[1];splay(tp1, NIL);splay(tp2, root);}else{checkmax(ret1, t1);splay(tp2, root);}}if(ABS(ret-ret1) > EPS) throw "w";*/return ret;}} spt;double Y(int ind){ return table[ind]/(A[ind]*R[ind]+B[ind]);}double X(int ind){ return table[ind]/(A[ind]*R[ind]+B[ind])*R[ind];}double get() { char c; while((c=getchar())<'0'||c>'9'); double a=c-'0',b=1; while((c=getchar())>='0'&&c<='9')a=a*10+c-'0'; if(c=='.') while((c=getchar())>='0'&&c<='9')b*=10.0,a=a+(c-'0')/b; return a; } int main(){int n, s;//freopen("d:\\in.txt", "r", stdin);while(~scanf("%d%d", &n, &s)){spt.init();for(int i = 1; i <= n; ++i){A[i] = get();B[i] = get();R[i] = get();}table[1] = s;spt.insert(X(1), Y(1));for(int i = 2; i <= n; ++i){table[i] = max(table[i-1], spt.query(i));spt.insert(X(i), Y(i));}printf("%.3f\n", table[n]);}return 0;}