NOI2007貨幣兌換CASH 斜率DP CDQ分治
按照http://hzwer.com/3508.html改的……
勉強能當自己板子用吧…… 感覺細節好多,
要注意各種細節,比如兩個點重合啊,兩個點的斜率不存在啊種種種種……
太累了,但是我感覺判斷2個點斜率差,可以用我的方法更好一些~
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #define ll long long using namespace std; const int maxn = 100005; const double inf = 1e12;//-inf就是負無窮了 const double eps = 1e-9; double f[maxn]={0}; struct node { int id; double x, y, k; double a, b, r; }p[maxn], t[maxn]; node stk[maxn]; int top, n; bool operator <(node A, node B)//斜率倒著排序,為了在凸殼上計算方便 { return A.k > B.k; } bool check(node A, node B, node C)// A,B的斜率如果<=B,C斜率,則為true { double a=(B.y-A.y)*(C.x-B.x); double b=(C.y-B.y)*(B.x-A.x); if (a==b) return true; if (a>0 && b>0) return a>b; if (a<0 && a<0) return a<b; if (a<0) return true; return false; } double xie(node A, node B) { if (A.y==B.y) return inf; return (A.y-B.y)/(A.x-B.x); } double getDP(int k, node A) { return p[k].a*A.x +p[k].b*A.y; } void solve(int l, int r) { if (l == r) { f[l]=max(f[l],f[l-1]); p[l].y=f[l]/(p[l].a*p[l].r+p[l].b); p[l].x=p[l].r*p[l].y; return; } int mid = l + (r-l)/2; int l1 =l, l2 = mid + 1; for (int i = l; i <=r; ++ i) if (p[i].id <= mid) t[l1++] = p[i]; else t[l2++] = p[i]; for (int i = l; i <= r; ++ i) p[i] = t[i]; solve(l, mid); top = 0;//[a[top]為棧頂元素,top=0表示空棧,棧內有0個元素。] //開始做一次凸殼,之前的所有的點,都是按照x座標排序好了,因為已經不需要求解其f值,已經不需要管順序了 node tmp; for (int i = l; i<= mid; ++ i) { while (top > 1 && check(stk[top- 1], stk[top], p[i])) top--; stk[++top] = p[i]; } tmp; tmp.x=0; tmp.y=0; stk[++top]=tmp;//為了讓最後一個節點出現異常,即位最後一個斜率巨大無比是正數。而遞減的序列出現正數,不可能更優 int pos=1; for (int i = mid + 1; i <= r; ++ i) { while (pos <=top && getDP(i, stk[pos]) <= getDP(i, stk[pos+1])) pos++; f[p[i].id] = max(f[p[i].id], getDP(i, stk[pos])); } solve(mid + 1, r); l1=l, l2=mid+1; //現在已經計算完l,r區間的所有值,並且實際上,已經都取得最優解了。需要給他們按照x座標,歸併排序了 for (int i = l; i <= r; ++ i) if (l2 > r|| l1 <=mid && (p[l1].x < p[l2].x || p[l1].x==p[l2].x && p[l1].y>p[l2].y)) t[i] = p[l1++]; else t[i] = p[l2++]; for (int i = l; i <=r; ++ i) p[i] = t[i]; } int main() { freopen("cash.in","r",stdin); freopen("cash.ans","w",stdout); scanf("%d%lf",&n, &f[0]); for (int i = 1; i <= n; ++ i) { scanf("%lf%lf%lf", &p[i].a, &p[i].b, &p[i].r); p[i].id = i; p[i].k = -p[i].a/p[i].b; if (p[i].a==0) p[i].k=0; } sort(p + 1, p + 1 + n); solve(1, n); printf("%.3lf\n", f[n]); return 0; }
相關推薦
NOI2007貨幣兌換CASH 斜率DP CDQ分治
按照http://hzwer.com/3508.html改的…… 勉強能當自己板子用吧…… 感覺細節好多, 要注意各種細節,比如兩個點重合啊,兩個點的斜率不存在啊種種種種…… 太累了,但是我感覺判斷2個點斜率差,可以用我的方法更好一些~ #include<io
[BZOJ1492][NOI2007]貨幣兌換Cash(斜率優化+CDQ分治)
是個 並且 define 支付 ont png page 方程 while 1492: [NOI2007]貨幣兌換Cash Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 5838 Solved: 2345[Submit]
1492: [NOI2007]貨幣兌換Cash|動態規劃|cdq分治
好厲害的分治貼程式碼 可以參考論文 #include<cstdio> #include<cstdlib> #include<cstring> #include&l
【BZOJ 1492】 [NOI2007]貨幣兌換Cash 斜率優化DP
ostream 解決 double col esp ash pre 優秀 不用 先說一下斜率優化:這是一種經典的dp優化,是OI中利用數形結合的思想解決問題的典範,通常用於優化dp,有時候其他的一些決策優化也會用到,看待他的角度一般有兩種,但均將決策看為二維坐標系上的點
BZOJ 1492 [NOI2007]貨幣兌換Cash:斜率優化dp + cdq分治
turn inline problem class fin 復雜度 所有 stdio.h isp 傳送門 題意 初始時你有 $ s $ 元,接下來有 $ n $ 天。 在第 $ i $ 天,A券的價值為 $ A[i] $ ,B券的價值為 $ B[i] $ 。 在第 $ i
[bzoj1492][cdq分治][斜率優化][NOI2007]貨幣兌換Cash
1492: [NOI2007]貨幣兌換Cash Time Limit: 5 Sec Memory Limit: 64 MB Submit: 5063 Solved: 2075 [Submit][Status][Discuss] Description
bzoj [NOI2007]貨幣兌換Cash (cdq分治+斜率優化 )
#include<cstdio> #include<cmath> #include<queue> #include<stack> #include<string> #include<cstring> #include<iostrea
BZOJ1492: [NOI2007]貨幣兌換Cash
小數 arr ati 隨著 輸入 分治算法 || 圖片 strong Description 小Y最近在一家金券交易所工作。該金券交易所只發行交易兩種金券:A紀念券(以下簡稱A券)和 B紀念券(以下簡稱B券)。每個持有金券的顧客都有一個自己的帳戶。金券的數目可以是一個實數。
bzoj1492 NOI2007 貨幣兌換Cash
題目描述 題解: 題目都提示了, 很明顯要導一波式子: $$dp[i]=max( dp[i-1] , \frac{ dp[j] } { A[j]*R[j]+B[j] } * (A[i]*R[j]+B[i]))$$ 後面那個東西相當與將第j天的R[j]個A和1個B綁在一起。 $dp[i-1]$沒什麼
[bzoj 1492][NOI2007]貨幣兌換Cash
傳送門 Solution 一道很早以前做過的題,突然想補篇部落格…… 方程什麼的就不展現了。 反正斜率優化的題都挺好寫的。 斜率優化的核心是: \[ \frac{Y_j-Y_k}{X_j-X_k}\leq W_i \] 可以把每個決策\(j\)用兩個數\(X_j\),\
bzoj 1492: [NOI2007]貨幣兌換Cash
測試資料設計使得精度誤差不會超過10-7。 對於40%的測試資料,滿足N ≤ 10; 對於60%的測試資料,滿足N ≤ 1 000; 對於100%的測試資料,滿足N ≤ 100 000; 動態維護凸包+斜率優化 CDQ分治+斜率優化 剛好對於前面正在做的CDQ分治和斜率優化用這題和NOI2014購票來
LUOGU P4027 [NOI2007]貨幣兌換 (斜率優化+CDQ分治)
ace sca pre noi 正是 while opened 一個點 const 傳送門 解題思路 題目裏有兩句提示一定要看清楚,要不全買要不全賣,所以dp方程就比較好列,f[i]=max(f[j]*rate[j]*a[i])/(rate[j]*a[j]+b[j])+
[NOI2007]貨幣兌換 「CDQ分治實現斜率優化」
首先每次買賣一定是在某天 $k$ 以當時的最大收入買入,再到第 $i$ 天賣出,那麼易得方程: $$f_i = \max \{\frac{A_iRate_kf_k}{A_kRate_k + B_k} + \frac{B_if_k}{A_kRate_k + B_k}\}$$ 再令 $$\left\{\be
洛谷P4027 [NOI2007]貨幣兌換(dp 斜率優化 cdq 二分)
題意 題目連結 Sol 解題的關鍵是看到題目裡的提示。。。 設\(f[i]\)表示到第\(i\)天所持有軟妹幣的最大數量,顯然答案為\(max_{i = 1}^n f[i]\) 轉移為\(f_i = max(f_{i - 1}, A_i \frac{f_j R_j}{A_j R_j + B_j} +
【BZOJ2149】拆遷隊(斜率優化DP+CDQ分治)
題目: BZOJ2149 分析: 先吐槽一下題意:保留房子反而要給賠償金是什麼鬼哦…… 第一問是一個經典問題。直接求原序列的最長上升子序列是錯誤的。比如\(\{1,2,2,3\}\),選擇\(\{1,2,3\}\)不改變後會發現無論如何修改都無法變成一個嚴格上升序列。只能選擇\(\{1,2\}\),把
bzoj-1492 貨幣兌換Cash (1)——平衡樹維護凸包
ota scan efi mod 結構 inf borde -a 中序 題意: 有n天和m的初始金錢,用來購買AB兩種紀念券; n天裏每天都有AB的價格。每天能夠進行這種操作。 1.賣出手中x%的紀念券(AB分別都賣出x%)。 2.用x的金錢買入紀念券。買入AB券的比例
BZOJ1492 [NOI2007]貨幣兌換
right 並且 con 整數 一次 clas 他還 優點 i++ Description 小Y最近在一家金券交易所工作。該金券交易所只發行交易兩種金券:A紀念券(以下簡稱A券)和 B紀念券(以下 簡稱B券)。每個持有金券的顧客都有一個自己的帳戶。金券的數目可以是一個
【BZOJ2726】[SDOI2012]任務安排 斜率優化+cdq分治
時間 斜率 bool print pan i+1 main 最小 可能 【BZOJ2726】[SDOI2012]任務安排 Description 機器上有N個需要處理的任務,它們構成了一個序列。這些任務被標號為1到N,因此序列的排列為1,2,3...N。這N個任務被
BZOJ1492:[NOI2007]貨幣兌換——題解
單調性 blank nod 描述 else 時間 con math amp http://www.lydsy.com/JudgeOnline/problem.php?id=1492 (題目描述太長了不粘貼了……) …&helli
[Noi2014]購票 BZOJ3672 點分治+斜率優化+CDQ分治
input CP using rar 暴力 out def #define bubuko Description 今年夏天,NOI在SZ市迎來了她30周歲的生日。來自全國 n 個城市的OIer們都會從各地出發,到SZ市參加這次盛會。全國的城市構成了一棵以SZ市