BZOJ 1492 斜率优化dp && cdq分治

        很容易得出转移方程,f[i]=max{ans,Rate[j]*F[j]*A[i]+F[j]*B[i]}/(rate[i]*a[i]+b[i]),其中f[i]表示在第i天所获得的的最多的B卷

        然后,我们发现会超时,我们稍微化简一下,由f[i] = (rate[j]*f[j]*A[i]+f[j]*B[i])/(rate[i]*A[i]+B[i])得

                                      f[i]*(rate[i]*A[i]+B[i])/A[i] = (-B[i]/A[i])*f[j]+f[j]*rate[j]

        相当于我们需要维护一个数据结构,满足

        1.插入一个点(f[i],f[i]*rate[i])

        2.给定负斜率-B[i]/A[i],求最大截距

        嗯,平衡树上吧

       

#include <cstdio>
#include <cmath>
#include <set>
#include <iostream>

using namespace std;

const int MAXN = 100001;
const double INF = 10000001;

int n;
double s;
double f[MAXN];
double A[MAXN],B[MAXN],rate[MAXN];
double ans;
bool F;

struct point
{
	double x,y,k;
	bool operator < (const point &rhs) const
	{
		if (!F) return x < rhs.x || (x == rhs.x && y < rhs.y);
		else return k > rhs.k;
	}
	point() {}
	point(double _x,double _y,double _k):x(_x),y(_y),k(_k){}
};

typedef point Vector;

Vector operator + (Vector A,Vector B){return (Vector){A.x+B.x,A.y+B.y,0};}
Vector operator - (point A,point B){return (Vector){A.x-B.x,A.y-B.y,0};}
inline double cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}

set <point> S;
set <point> :: iterator it1,it2;

inline double slope(point A,point B)
{
	return (A.y-B.y)/(A.x-B.x);
}

inline double cut(double k,point p)
{
	return p.y-p.x*k;
} 

bool judge(point p)
{
	F = false;
	if (S.size() == 1) return false;
	if (p < *S.begin() || *(--S.end()) < p) return false;
	it1 = it2 = S.lower_bound(p);
	it1--;
	if (cross(*it2-*it1,p-*it1) < 0) return true;
	return false;
}

void insert(point p)
{
	if (judge(p)) return;
	it1 = it2 = --S.lower_bound(p);
	if (it2 != S.begin()) it2--;
	while (it1 != S.begin())
	{
		if (cross(p-*it2,*it1-*it2) < 0) S.erase(it1);
		else break;
		it1 = it2;
		if (it2 != S.begin()) it2--;
	}
	it1 = it2 = S.lower_bound(p);
	it2++;
	while (it1 != S.end() && it2 != S.end())
	{
		if (cross(p-*it2,*it1-*it2) > 0) S.erase(it1);
		else break;
		it1 = it2;
		if (it2 != S.end()) it2++;
	}
	it1 = it2 = S.lower_bound(p);
	if (it1 != S.begin())
	{
		it1--;
		point temp = *it1;
		temp.k = slope(temp,p), S.erase(it1), S.insert(temp);
	}
	if (it2 != S.end())
	{
		point temp = *it2;
		p.k = slope(temp,p);
	}
	S.insert(p);
	point temp = *(--S.end());
	temp.k = INF;
	S.erase(--S.end()), S.insert(temp);
}

int main()
{
	scanf("%d%lf",&n,&s);
	for (int i=1;i<=n;i++) scanf("%lf%lf%lf",&A[i],&B[i],&rate[i]);
	ans = s;
	f[1] = ans/(rate[1]*A[1]+B[1]);
	S.insert((point){f[1],f[1]*rate[1],INF});
	for (int i=2;i<=n;i++)
	{
		F = true;
		point temp;
		temp = *S.lower_bound((point){0,0,-B[i]/A[i]});
		f[i] = max(ans,cut(-B[i]/A[i],temp)*A[i])/(rate[i]*A[i]+B[i]);
		ans = max(ans,rate[i]*f[i]*A[i]+f[i]*B[i]);
		temp = *--S.lower_bound((point){0,0,-B[i]/A[i]});
		f[i] = max(ans,cut(-B[i]/A[i],temp)*A[i])/(rate[i]*A[i]+B[i]);
		ans = max(ans,rate[i]*f[i]*A[i]+f[i]*B[i]);
		insert((point){f[i],f[i]*rate[i],0});
	}
	printf("%.3lf\n",ans);
	return 0;
}


        鉴于那个时候还没有set,splay写起来就是要死要死的,那么我们还可以使用cdq分治,说起来简单,还不如直接写动态凸包

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

using namespace std;

const int MAXN = 100001;
const double INF = 10000001;

int n;
double s;
double f[MAXN];
double A[MAXN],B[MAXN],rate[MAXN];
double ans;
bool F;

struct point
{
	double x,y;
	bool operator < (const point &rhs) const
	{
		return x < rhs.x || (x == rhs.x && y < rhs.y);
	}
};

typedef point Vector;

Vector operator + (Vector A,Vector B){return (Vector){A.x+B.x,A.y+B.y};}
Vector operator - (point A,point B){return (Vector){A.x-B.x,A.y-B.y};}
inline double cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}

int convex_size;
point P[MAXN];
point convex[MAXN];

inline double slope(point A,point B)
{
	return (A.y-B.y)/(A.x-B.x);
}

inline double cut(double k,point p)
{
	return p.y-p.x*k;
} 

int find(double k)
{
	int l = 1, r = convex_size-1;
	while (l+1 != r && l < r)
	{
		int mid = (l+r)/2;
		if (slope(convex[mid],convex[mid+1]) < k) r = mid;
		else l = mid;
	}
	return l;
}

void solve(int l,int r)
{
	if (l == r)
	{
		int t = find(-B[l]/A[l]);
		f[l] = max(f[l]*(rate[l]*A[l]+B[l]),cut(-B[l]/A[l],convex[t])*A[l])/(rate[l]*A[l]+B[l]);
		ans = max(ans,f[l]*rate[l]*A[l]+f[l]*B[l]);
		if (t != convex_size-1) t++;
		f[l] = max(f[l]*(rate[l]*A[l]+B[l]),cut(-B[l]/A[l],convex[t])*A[l])/(rate[l]*A[l]+B[l]);
		f[l] = max(f[l],ans/(rate[l]*A[l]+B[l]));
		ans = max(ans,f[l]*rate[l]*A[l]+f[l]*B[l]);
		P[l] = (point){f[l],f[l]*rate[l]};
		return;
	}
	int mid = (l+r)/2;
	solve(l,mid);
	convex_size = 0;
	for (int i=l;i<=mid;i++)
	{
		while (convex_size > 1 && (cross(convex[convex_size]-convex[convex_size-1],P[i]-convex[convex_size-1])) > 0) convex_size--;
		convex[++convex_size] = P[i];
	}
	convex[++convex_size] = (point){INF,INF};
	for (int i=mid+1;i<=r;i++)
	{
		int t = find(-B[i]/A[i]);
		f[i] = max(f[i]*(rate[i]*A[i]+B[i]),cut(-B[i]/A[i],convex[t])*A[i])/(rate[i]*A[i]+B[i]);
		if (t != convex_size-1) t++;
		f[i] = max(f[i]*(rate[i]*A[i]+B[i]),cut(-B[i]/A[i],convex[t])*A[i])/(rate[i]*A[i]+B[i]);
	}
	solve(mid+1,r);
	inplace_merge(P+l,P+mid+1,P+r+1); 
}

int main()
{
    scanf("%d%lf",&n,&s);
	for (int i=1;i<=n;i++) scanf("%lf%lf%lf",&A[i],&B[i],&rate[i]);
	ans = s;
	solve(1,n);
	printf("%.3lf\n",ans);
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值