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

【NOI2007】貨幣兌換

今天聽了crazy和samjia的NOI雜(砸)題選講,感覺自己萌萌噠~
於是就來怡情地寫了這道題。

Description

額(⊙o⊙)…,這個不好說啊。(語文不好不好裱我)
還是貼圖吧。
這裡寫圖片描述
這裡寫圖片描述
n<=10^5

Solution

咳咳,希望大家都看懂題了。
一個很明顯的貪心思路就是,我們每天要不全買,要不全賣。
因為一有利益我們就去佔,一有虧損我們就不碰。
那麼我們可以有dp方程:

F[i]=max(x[j]a[i]+y[j]b[i],F[i1])
因為你一天可以什麼都不淦。
其中x[i]表示第i天最多能獲得的A卷數量,y[i]表示B卷數量。
那麼x
[i]=F[i]/(A[i]Rate[i]+B[i])Rate[i]

y[i]=F[i]/(A[i]Rate[i]+B[i])
這樣Dp是N^2的,我們考慮優化。
設j是最優決策,那麼F[i]=x[j]a[i]+y[j]b[i]
於是y[j]=a[i]b[i]x[j]+F[i]b[i]
發現這是一次函式的形式。我們想讓截距最大。
於是我們可以維護一個凸包,因為斜率一定,使截距最大的點一定在凸包上。
以x為x軸,y為y軸建立平面直角座標系。
但是,x[i]和-a[i]/b[i]不見得單調。
所以我們就是要動態維護一個凸包,然後求某個斜率的位置。
splay大法好!splay大法好!splay大法好!
你每次找到i左邊最後一個斜率使得它仍然遞增的點,和右邊第一個使得它遞增的的點。
然後刪點就好了。不要忘了判斷加上這個點後是否還是凸包。

Code

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 100005
using namespace std;
typedef double db;
const db inf=0x7fffffff;
const db ep=1e-5;
int n,fa[N],t[N][2],root;
db f[N],x[N],y[N],a[N],b[N],r[N],lk[N],rk[N];
int
son(int x) { if (t[fa[x]][0]==x) return 0;else return 1; } void rotate(int x) { int y=fa[x],z=son(x);fa[x]=fa[y]; if (fa[y]) t[fa[y]][son(y)]=x; if (t[x][1-z]) fa[t[x][1-z]]=y; fa[y]=x;t[y][z]=t[x][1-z];t[x][1-z]=y; } void splay(int x,int y) { while (fa[x]!=y) { if (fa[fa[x]]!=y) if (son(x)==son(fa[x])) rotate(fa[x]); else rotate(x); rotate(x); } if (!y) root=x; } void insert(int &v,int f,int id) { if (!v) {v=id;fa[v]=f;splay(v,0);return;} if (x[id]<=x[v]+ep) insert(t[v][0],v,id); else insert(t[v][1],v,id); } db getk(int i,int j) { if (abs(x[j]-x[i])<ep) return -inf; else return ((y[j]-y[i])/(x[j]-x[i])); } int pre(int x) { int y=t[x][0],z=x; while (y) if (getk(y,x)<=lk[y]+ep) z=y,y=t[y][1]; else y=t[y][0]; return z; } int suc(int x) { int y=t[x][1],z=x; while (y) if (getk(x,y)+ep>=rk[y]) z=y,y=t[y][0]; else y=t[y][1]; return z; } void updata(int x) { splay(x,0); if (t[x][0]) { int left=pre(x);splay(left,x);t[left][1]=0; lk[x]=rk[left]=getk(left,x); } else lk[x]=inf; if (t[x][1]) { int right=suc(x);splay(right,x);t[right][0]=0; rk[x]=lk[right]=getk(x,right); } else rk[x]=-inf; if (lk[x]<=rk[x]+ep) { root=t[x][0];t[root][1]=t[x][1]; fa[t[x][1]]=t[x][0];fa[x]=0; rk[root]=lk[t[root][1]]=getk(root,t[root][1]); } } int find(int v,db k) { if (!v) return 0; if (lk[v]+ep>=k&&k+ep>=rk[v]) return v; if (k>lk[v]) return find(t[v][0],k); else return find(t[v][1],k); } int main() { scanf("%d%lf",&n,&f[0]); fo(i,1,n) scanf("%lf%lf%lf",&a[i],&b[i],&r[i]); fo(i,1,n) { int j=find(root,-a[i]/b[i]); f[i]=max(f[i-1],x[j]*a[i]+y[j]*b[i]); y[i]=f[i]/(a[i]*r[i]+b[i]); x[i]=y[i]*r[i]; insert(root,0,i); updata(i); } printf("%.3lf",f[n]); }

相關推薦

BZOJ1492NOI2007貨幣兌換

view .cn one src ostream 不清楚 span splay 方案 我果然不會斜率優化 原題: 小Y最近在一家金券交易所工作。該金券交易所只發行交易兩種金券:A紀念券(以下簡稱A券)和 B紀念券(以下 簡稱B券)。每個持有金券的顧客都有一個自己的帳戶。金券

NOI2007貨幣兌換

今天聽了crazy和samjia的NOI雜(砸)題選講,感覺自己萌萌噠~ 於是就來怡情地寫了這道題。 Description 額(⊙o⊙)…,這個不好說啊。(語文不好不好裱我) 還是貼圖吧。 n<=10^5 Solution

BZOJ1492NOI2007貨幣兌換

【分析】     首先要利用一個貪心的思想,就是在同一天要麼把錢全部換成金劵,要麼把金劵全部換成錢。     於是設f[i]為第i天能得到的最多的錢,x[i]與y[i]分別表示用第i天換來的錢全部換取A、B劵的數量,那麼有f[i]=max{a[i]*x[j]+b[i]*

BZOJ1492NOI2007貨幣兌換(動態規劃,CDQ分治,Splay)

題面 BZOJ 洛谷 Description 小Y最近在一家金券交易所工作。該金券交易所只發行交易兩種金券:A紀念券(以下簡稱A券)和 B紀念券(以下 簡稱B券)。每個持有金券的顧客都有一個自己的帳戶。金券的數目可以是一個實數。每天隨著市場的起伏波

NOI2007社交網絡

printf con blog color 網絡 () for 使用 ++ Description 在社交網絡(social network)的研究中,我們常常使用圖論概念去解釋一些社會現象。不妨看這樣的一個問題。在一個社交圈子裏有n個人,人與人之間有不同程度的關系。

JZOJ5962NOIP2018貨幣系統

description 在網友的國度中共有 n 種不同面額的貨幣,第 i 種貨幣的面額為 a[i],你可以假設每一種貨幣都有無窮多張。為了方便,我們把貨幣種數為 n、面額陣列為 a[1…n] 的貨幣系統記作 (n,a)。 在一個完善的貨幣系統中,每一個非負整數的金額 x 都應該可

BZOJ1494NOI2007生成樹計數

【題目連結】 【思路要點】 寫個矩陣樹定理的暴力,求出對於輸入的kk,NN在100以內的結果。 執行BM演算法,我們發現答案是一個至多46階的線性遞推。 然後求它的第NN項就好了。 時間複雜度O(R4+R2LogN)O(R4+R2

BZOJ1494NOI2007生成樹計數(動態規劃,矩陣快速冪)

題面 Description 最近,小棟在無向連通圖的生成樹個數計算方面有了驚人的進展,他發現: ·n個結點的環的生成樹個數為n。 ·n個結點的完全圖的生成樹個數為n^(n-2)。這兩個發現讓小棟欣喜若狂,由此更加堅定了他繼續計算生成樹個數的 想法,他

BZOJ 1492 [NOI2007]貨幣兌換Cash 斜率優化DP

ostream 解決 double col esp ash pre 優秀 不用   先說一下斜率優化:這是一種經典的dp優化,是OI中利用數形結合的思想解決問題的典範,通常用於優化dp,有時候其他的一些決策優化也會用到,看待他的角度一般有兩種,但均將決策看為二維坐標系上的點

Luogu P4027NOI2007 貨幣兌換

題目連結 題目描述 小 Y 最近在一家金券交易所工作。該金券交易所只發行交易兩種金券:A 紀念券(以下簡稱 A 券)和 B 紀念券(以下簡稱 B 券)。每個持有金券的顧客都有一個自己的帳戶。金券的數目可以是一個實數。 每天隨著市場的起伏波動,兩種金券都有自己當時

BZOJ1492 [NOI2007]貨幣兌換

right 並且 con 整數 一次 clas 他還 優點 i++ Description 小Y最近在一家金券交易所工作。該金券交易所只發行交易兩種金券:A紀念券(以下簡稱A券)和 B紀念券(以下 簡稱B券)。每個持有金券的顧客都有一個自己的帳戶。金券的數目可以是一個

例9.17貨幣系統

一個 for cst 貨幣 ont 方案 tdi long cout 【例9.17】貨幣系統 鏈接:http://ybt.ssoier.cn:8088/problem_show.php?pid=1273 時間限制: 1000 ms 內存限制: 65536

BZOJ1491 [NOI2007]社交網絡 floyd

long 重要 表示 lin n) 二次 src bug oid 題目 在社交網絡(socialnetwork)的研究中,我們常常使用圖論概念去解釋一些社會現象。不妨看這樣的一個問題。 在一個社交圈子裏有n個人,人與人之間有不同程度的關系。我們將這個關系網絡對應到一個n個結

BZOJ1492: [NOI2007]貨幣兌換Cash

小數 arr ati 隨著 輸入 分治算法 || 圖片 strong Description 小Y最近在一家金券交易所工作。該金券交易所只發行交易兩種金券:A紀念券(以下簡稱A券)和 B紀念券(以下簡稱B券)。每個持有金券的顧客都有一個自己的帳戶。金券的數目可以是一個實數。

BZOJ1492:[NOI2007]貨幣兌換——題解

單調性 blank nod 描述 else 時間 con math amp http://www.lydsy.com/JudgeOnline/problem.php?id=1492 (題目描述太長了不粘貼了……) …&helli

[BZOJ1492][NOI2007]貨幣兌換Cash(斜率優化+CDQ分治)

是個 並且 define 支付 ont png page 方程 while 1492: [NOI2007]貨幣兌換Cash Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 5838 Solved: 2345[Submit]

BZOJ 1492 [NOI2007]貨幣兌換Cash:斜率優化dp + cdq分治

turn inline problem class fin 復雜度 所有 stdio.h isp 傳送門 題意 初始時你有 $ s $ 元,接下來有 $ n $ 天。 在第 $ i $ 天,A券的價值為 $ A[i] $ ,B券的價值為 $ B[i] $ 。 在第 $ i

動態規劃貨幣面值

用例 數字 一行 元素 sample ont con 包含 flag 題目描述 魔法世界發行了很多不同面值的紙幣,試求出用這些紙幣進行任意的組合不能表示的最小面值是多少。 輸入 輸入包含多個測試用例,每組測試用例的第一行輸入一個整數N(N≤100)表示流通的紙幣面額數量

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])+

洛谷P5020貨幣系統

題目大意:給定 N 個數,求在這 N 個數中至少選出幾個數能表示出所有數字,輸出最少的個數。 題解:由於只有小的數字可以表示大的數字,因此首先需要對這 N 個數字進行從小到大排序。排序之後就變成一道不定個數的數字組合問題,即:完全揹包思想。遍歷每一個數字,若該數字不能由之前的數字表示出來,則將答案加一,並將