CDQ分治+ DP BZOJ 1492 Cash

題目鏈接:[NOI2007]貨幣兌換Cash

分析請見CDQ論文: 從《Cash》談一類分治算法的應用

代碼如下:

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>

using namespace std;
const int maxn=200000+5;
const double inf= 999999999999.00, eps= 1e-9; 

int n,S;
int Q[maxn],rear;
double f[maxn];

struct node{
	int id;
	double x,y,a,b,k,rate;
	// x: 第一種商品的數量 y: 第二種商品的數量. 
	bool operator < (const node p) const {    // 按斜率 k= - a[i]/b[i] 降序排序 .
		return k > p.k;  	
	}
	void put(){
		cout<<x<<" "<<y<<endl; 
	} 
}s[maxn],temp[maxn];

double slope(int A,int B){
	if(B==0) return  -inf;
	if( fabs(s[A].x-s[B].x)< eps ) return inf;
	return (s[A].y-s[B].y) / (s[A].x-s[B].x);
}

void Solve(int L,int R){
	if(L==R){
		f[L]= max(f[L],f[L-1]);
		s[L].y= f[L]/(s[L].rate*s[L].a+s[L].b);
		s[L].x= s[L].y*s[L].rate;
		return ;
	}
	int mid= (L+R)>>1;
	int i=L,j=mid+1,p;
	// 按照原序排序,保證左邊能更新右邊,而且左右區間中 k= -a[i]/b[i]  也是分別遞減的.
	for(p=L;p<=R;p++){
		if(s[p].id<=mid) temp[i++]= s[p];
		else temp[j++]= s[p];
	}
	for(i=L;i<=R;i++)s[i]= temp[i];
	Solve(L,mid);
	//維護左邊的凸包,左區間已經按照x排好序.
	rear=0; 
	for(i=L; i<=mid; i++){
		while(rear>1 && slope(Q[rear],Q[rear-1])< slope(Q[rear-1],i)+eps) rear--;
		Q[++rear]= i;
	} 
	Q[++rear]=0; 
	// 用左區間更新右區間 
	for(i=mid+1, j=1 ;i<=R;i++){
		while(j<rear && slope(Q[j],Q[j+1])+eps > s[i].k) j++;
		//cout<< Q[j]<<" -> "<<s[i].id<<" "<<Q[j+1]<<" "<<s[i].k<<endl; 
		//s[Q[j]].put();
		f[s[i].id]= max(f[s[i].id], s[Q[j]].x*s[i].a+s[Q[j]].y*s[i].b);
	}
	Solve(mid+1,R);
	//按照 x值大小歸併排序
	i=L; j=mid+1;
	for(p=L;p<=R && i<=mid && j<=R;p++){
		
		if(s[i].x<s[j].x || (fabs(s[i].x-s[j].x)<eps && s[i].y<s[j].y)) temp[p]= s[i++];
		else temp[p]= s[j++];
	} 
	while(i<=mid) temp[p++]= s[i++];
	while(j<=R) temp[p++]= s[j++];
	for(i=L;i<=R;i++) s[i]=temp[i];
}

int main(){
	int i,j;
	scanf("%d%lf",&n,&f[0]);
	for(i=1;i<=n;i++){
		scanf("%lf%lf%lf",&s[i].a,&s[i].b,&s[i].rate);
		s[i].id=i; s[i].k= -s[i].a/s[i].b;
	}
	sort(s+1,s+1+n);
	Solve(1,n);
	//for(i=1;i<=n;i++)
	printf("%.3lf\n",f[n]);
	return 0;
}


發佈了195 篇原創文章 · 獲贊 14 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章