1. 程式人生 > >1492: [NOI2007]貨幣兌換Cash|動態規劃|cdq分治

1492: [NOI2007]貨幣兌換Cash|動態規劃|cdq分治

好厲害的分治貼程式碼

可以參考論文

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#include<iostream>
#define T 120000
#define eps 1e-9
#define inf 1e9
using namespace std;
struct W
{
	double x,y,k,a,b,rate;
	int id;
}p[T],q[T],t[T];
double f[T];
int st[T];
int n;
bool cmp(W a,W b){return a.k<b.k;}
double getk(int i,int j)
{
    if (i==0) return -inf;
    if (j==0) return inf;
    if (fabs(p[i].x-p[j].x)<=eps) return -inf;
    return (p[i].y-p[j].y)/(p[i].x-p[j].x);
}
void solve(int l,int r)
{
	if(l==r)
	{
		f[l]=max(f[l],f[l-1]);
		p[l].y=f[l]/(q[l].a*q[l].rate+q[l].b);
		p[l].x=p[l].y*q[l].rate;
		return ;
	}
	int mid=l+r>>1,l1=l,l2=mid+1;
	
	for(int i=l;i<=r;i++)
	    if(q[i].id<=mid) t[l1++]=q[i];
	    else  t[l2++]=q[i];
	for(int i=l;i<=r;i++) q[i]=t[i];
	solve(l,mid);
	
	int top=0;
	for(int i=l;i<=mid;i++)
	{
		while(top>=2&&getk(i,st[top])>getk(st[top],st[top-1])) top--;
		st[++top]=i;
	}
	
	int j=1;
    for (int i=r;i>=mid+1;i--)
    {
        while (j<top&&q[i].k<getk(st[j],st[j+1])) j++;
        f[q[i].id]=max(f[q[i].id],p[st[j]].x*q[i].a+p[st[j]].y*q[i].b);
    }  
	
	solve(mid+1,r);
	l1=l,l2=mid+1;
    for (int i=l;i<=r;i++)
        if ((p[l1].x<p[l2].x||l2>r)&&l1<=mid) t[i]=p[l1++];
        else t[i]=p[l2++];
    for (int i=l;i<=r;i++) p[i]=t[i];
}
int main()
{
	scanf("%d%lf",&n,&f[0]);
	for(int i=1;i<=n;i++)
	{
		scanf("%lf%lf%lf",&q[i].a,&q[i].b,&q[i].rate);
		q[i].k=-q[i].a/q[i].b;
		q[i].id=i;
	}
	sort(q+1,q+n+1,cmp);
	solve(1,n);
	printf("%.3lf\n",f[n]);
	return 0;
}