$NOI2007$ 货币兑换

\(NOI2007\)货币兑换

辣鸡题目毁我青春

刚看到这题的时候我一脸懵逼啊,问了一波\(fdf\)才把六十分推出来,然后强行理解了一波斜率和横坐标都不单调的斜率优化。理解了一下发现这不是傻逼题吗,然后我调斜率计算调到怀疑人生。

\(Part1\) 关于斜率不存在

这个很显然啊,但是我之前居然都没被卡过。

根据两个点纵坐标来判断到底是返回\(inf\)还是\(-inf\)

\(Part2\) 关于两点重合

两点的纵坐标也相等时,是返回\(-inf\)的!别问我为什么浮点数比较用等于号是有用的,估计他们掉精度是有一个法则的吧,掉成一样的了。

\(Part3\) 关于弹栈

浮点数比较真的真的不要忽略等于号,在弹栈的时候,斜率相等的情况是要弹掉的,不然的话会\(WA\),感觉可能是二分的时候会挂掉,这个等于号是很有用的。(我记得凸包也不能有三点共线吧)

挺裸的一道题,但是被上面的几个细节坑到了,积累一下,以后就不会出错了,挺好。

下面是\(CDQ\)写法的代码。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<queue>
#include<map>
#include<vector>
#define N 101000
#define EPS 1e-7
#define ll long long
#define RG register
#define inf 1e18+1

using namespace std;
inline int read(){
    RG int x=0,o=1; RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if(ch=='-') o=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=((x<<3)+(x<<1))+ch-'0',ch=getchar();
    return x*o;
}

int n,S,Q[N]; double f[N],a[N],b[N],r[N],ans;
struct mona { int id; double K,A,B; } s[N],p[N];
inline double Slope(const int &i,const int &j){
	if(fabs(s[j].A-s[i].A)<EPS) return s[i].B<s[j].B?inf:-inf;
	return (s[i].B-s[j].B)/(s[i].A-s[j].A);
}

inline void CDQ(int l,int r){
	if(l==r){
		f[l]=max(f[l],f[l-1]);
		s[l].A*=f[l],s[l].B*=f[l]; return ;
	}	int mid=l+r>>1;
	CDQ(l,mid); RG int top=1; Q[1]=0;
	for(RG int i=l;i<=mid;++i){
		while(top>1&&Slope(Q[top-1],Q[top])<=Slope(Q[top-1],i)) --top;
		Q[++top]=i;
	}
	for(RG int i=mid+1;i<=r;++i){
		int L=2,R=top,ans=1;
		while(L<=R){
			int Mid=L+R>>1;
			if(Slope(Q[Mid-1],Q[Mid])>s[i].K) L=Mid+1,ans=Mid;
			else R=Mid-1;
		}   f[i]=max(f[i],(-s[Q[ans]].A*s[i].K+s[Q[ans]].B)*b[i]);
	}	CDQ(mid+1,r);
	for(RG int l1=l,l2=mid+1,len=l;len<=r;++len)
		if((s[l1].A<s[l2].A&&l1<=mid)||l2>r) p[len]=s[l1++];
		else p[len]=s[l2++];
	for(RG int i=l;i<=r;++i) s[i]=p[i];
}

int main(){
	n=read(),S=read(),f[1]=S;
	for(RG int i=1;i<=n;++i) scanf("%lf%lf%lf",&a[i],&b[i],&r[i]);
	for(RG int i=1;i<=n;++i)
		s[i]=(mona) { i,-a[i]/b[i],r[i]/(a[i]*r[i]+b[i]),1.0/(a[i]*r[i]+b[i]) };
	CDQ(1,n); printf("%.3lf\n",f[n]);
}

posted @ 2018-10-17 17:35  Love_mona  阅读(143)  评论(0编辑  收藏  举报