1. 程式人生 > >NOI2007貨幣兌換CASH 斜率DP CDQ分治

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]貨幣兌換Cashcdq分治+斜率優化 )

#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市