BZOJ1492 貨幣兌換NOI2007
阿新 • • 發佈:2019-01-04
Problem
Solution
則表示第i天持有的最多的RMB,那麼當天持有的最多的金券則分別可以用其表示
將 中的 當做常量, 當做點則會發現這是一個直線標準方程,化簡一下,我們就需要最大化截距
然而其中的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;
}