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; }