BZOJ-1492-货币兑换cash-NOI2007-CDQ分治
生活随笔
收集整理的這篇文章主要介紹了
BZOJ-1492-货币兑换cash-NOI2007-CDQ分治
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
描述
分析
- CDQ分治的例題, 具體怎么分析看當時的課件.
- DP優化, 維護凸線, 斜率遞增.
- 說白了就是一個分治
- memcpy 不比 for 循環快
- 函數參數加引用比不加引用還慢了
- 自己推了一遍分析過程, 放代碼后面了
代碼
#include #include #include using namespace std;const int maxn = 100000 + 10; const double INF = 1e20; const double eps = 1e-9;struct Node {int id;double a, b, r, x, y, k;void read(int i) {id = i;scanf("%lf %lf %lf", &a, &b, &r);k = -a/b;}bool operator < (const Node& rhs) const {if(x < rhs.x) return 1;return fabs(x-rhs.x) < eps && y < rhs.y;}} A[maxn], T[maxn];bool cmpK(const Node& lhs, const Node& rhs) {return lhs.k > rhs.k; }double getK(Node i, Node j) {if(fabs(j.x-i.x) < eps) return INF;return (j.y-i.y) / (j.x-i.x); }int S[maxn]; double f[maxn];void solve(int L, int R) {if(L == R) {f[L] = max(f[L], f[L-1]);A[L].y = f[L] / (A[L].a * A[L].r + A[L].b);A[L].x = A[L].y * A[L].r;return;}int M = (L+R) >> 1;int p = L, q = M+1;for(int i = L; i <= R; i++) {Node& x = A[i];if(x.id <= M) T[p++] = A[i];else T[q++] = A[i];}for(int i = L; i <= R; i++) A[i] = T[i];solve(L, M);int top = 0;for(int i = L; i <= M; i++) {while(top > 1 && getK(A[S[top-2]], A[S[top-1]]) - getK(A[S[top-2]], A[i]) < eps) top--;S[top++] = i;}for(int i = M+1, j = 0; i <= R; i++) {while(j < top-1 && A[i].k - getK(A[S[j]], A[S[j+1]]) < eps) j++;Node &x = A[i], &y = A[S[j]];f[x.id] = max(f[x.id], y.x*x.a + y.y*x.b);}solve(M+1, R);p = L;q = M+1;for(int i = L; i <= R; i++)if(p <= M && (A[p] < A[q] || q > R)) T[i] = A[p++];else T[i] = A[q++];for(int i = L; i <= R; i++) A[i] = T[i]; }int main() {int n;scanf("%d %lf", &n, &f[0]);for(int i = 1; i <= n; i++) A[i].read(i);sort(A+1, A+n+1, cmpK);solve(1, n);printf("%.3lf\n", f[n]); } // S的現金在Rate = r時 可以買A(B)金券a(b)單位. a*A + b*B = S a/b = r => b = a/r a*A + a/r*B = S a(A + B/r) = S a = S*r / (A*r + B)// 第 i 天最多獲得的A金券的數量 f[i] = max{f[j] * A[j] + f[j]/r[j] * B[j], j < i} * r/(A[i]*r[i] + B[i])j better than k :f[j] * A[i] + f[j]/r[j] * B[i] > f[k] * A[i] + f[k]/r[k] * B[i]f[j] * A[i] + f[j]/r[k] * B[i] - f[k] * A[i] - f[k]/r[k] * B[i] > 0(f[j]-f[k])*A[i] + (f[j]/r[j] - f[k]/r[k])*B[i] > 0// 發現因不知道 f[j]和f[k] 的大小關系需要分類討論了, 不放設 f[j] < f[k]// 設 g[x] = f[x] / r[x], g[x]的意義也很清楚, 就是第 i 天最多獲得的B金券的數量(f[j]-f[k])*A[i] + (g[j]-g[k])*B[i] > 0(g[j]-g[k]) / (f[j]-f[k]) < -A[i]/B[i]// 明顯帶有斜率的意味了, 把 f[] 看作 x, g[] 看作 y// 那么可以看出在更新 i 的答案時, 把 i 之前的元素按 x(f[]) 從小到大排序// 如果 j 的后面存在一個 k 使得直線 jk 的斜率不小于 -A[i]/B[i]// 就說明 j 不優于 k// 為判斷 j 是否比后面所有點更優, 可以保存 j 之后使 jk 斜率最大的 k, 通過比較斜率判斷是否可以用 j 更新 i// 上面說的對于每個 j 都要保存一個使 jk 斜率最大的 k, 那么最后存下來點就組成一個凸線// 凸線上從第一個點開始斜率遞減, 所以更新答案要使被更新的區域 -A[i]/B[i] 遞減, 因此最開始要按 -A[i]/B[i] 從大到小排序// 來保證每一部分的 -A[i]/B[i] 都是有序的 與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的BZOJ-1492-货币兑换cash-NOI2007-CDQ分治的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ-3110-K大数查询-ZJOI
- 下一篇: BZOJ-2001-city城市建设-H