BZOJ1492 货币兑换NOI2007

版权声明:写得不好,转载请通知一声,还请注明出处,感激不尽 https://blog.csdn.net/As_A_Kid/article/details/85109431

Problem

BZOJ

Solution

C [ i ] C[i] 则表示第i天持有的最多的RMB,那么当天持有的最多的金券则分别可以用其表示

C [ i ] = max j = 1 i 1 ( A [ j ] a i + B [ j ] b i ) C[i]=\max_{j=1}^{i-1} (A[j]*a_i+B[j]*b_i)

C [ i ] C[i] 中的 a i , b i a_i,b_i 当做常量, ( A [ j ] , B [ j ] ) (A[j],B[j]) 当做点则会发现这是一个直线标准方程,化简一下,我们就需要最大化截距

y = a i b i x + C [ i ] b i y=-\frac {a_i} {b_i}x+\frac {C[i]} {b_i}

然而其中的x并不单调。那么怎么用CDQ维护动态凸包呢?

先把所有的询问按斜率排序,CDQ时按询问位置进行排序,就可以得到一个二维偏序关系。CDQ(l,r)表示解决f[l]…f[r]的值
先CDQ出左半边的凸包,然后我们就可以用左边的凸包依次更新右边的询问,因为第一次排序保证了询问斜率单调递增,所以不更优就直接弹栈即可。
最后把所有的点按照x轴进行排序,这样便于上层构建凸包。

Code

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#define fr first
#define se second
using namespace std;
typedef long long ll;
typedef pair<double,double> pii;
const int maxn=100010;
const double eps=1e-8,INF=1e9;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
struct data{
	double a,b,r,k;int id;
	bool operator < (const data &t)const{return k<t.k;}
}q[maxn],nq[maxn];
int n,tp,stk[maxn];
double f[maxn];
pii p[maxn],np[maxn];
double slope(pii a,pii b)
{
	if(fabs(a.fr-b.fr)<=eps) return INF*(b.se>=a.se?1:-1);
	return (b.se-a.se)/(b.fr-a.fr);
}
void cdq(int l,int r)
{
	if(l==r)
	{
		getmax(f[l],f[l-1]);
		p[l].fr=f[l]/(q[l].a+q[l].b/q[l].r);
		p[l].se=f[l]/(q[l].a*q[l].r+q[l].b);
		return ;
	}
	int m=(l+r)>>1,L=l,R=m+1;
	for(int i=l;i<=r;i++)
	{
		if(q[i].id<=m) nq[L++]=q[i];
		else nq[R++]=q[i];
	}
	memmove(q+l,nq+l,(r-l+1)*sizeof(q[0]));
	cdq(l,m);tp=0;
	for(int i=l;i<=m;i++)
	{
		while(tp>1&&slope(p[stk[tp-1]],p[stk[tp]])<slope(p[stk[tp]],p[i])) tp--;
		stk[++tp]=i;
	}
	for(int i=m+1;i<=r;i++)
	{
		while(tp>1&&slope(p[stk[tp-1]],p[stk[tp]])<q[i].k) tp--;
		getmax(f[q[i].id],q[i].a*p[stk[tp]].fr+q[i].b*p[stk[tp]].se);
	}
	cdq(m+1,r);L=l;R=m+1;
	for(int i=l;i<=r;i++)
	{
		if((p[L]<p[R]||R>r)&&L<=m) np[i]=p[L++];
		else np[i]=p[R++];
	}
	memmove(p+l,np+l,(r-l+1)*sizeof(p[0]));
}
int main()
{
	read(n);scanf("%lf",&f[0]);
	for(int i=1;i<=n;i++)
	{
		scanf("%lf%lf%lf",&q[i].a,&q[i].b,&q[i].r);
		q[i].k=-q[i].a/q[i].b;q[i].id=i;
	}
	sort(q+1,q+n+1);
	cdq(1,n);
	printf("%.3lf\n",f[n]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/As_A_Kid/article/details/85109431
今日推荐