您的位置:首页 > 其它

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

2015-01-29 20:14 471 查看
很容易得出转移方程,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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: