GMOJ4017逃跑
Posted stoorz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GMOJ4017逃跑相关的知识,希望对你有一定的参考价值。
题目
题目链接:https://gmoj.net/senior/#main/show/4017
Konrad, Delfador 和 Kalenz 一行人又喜闻乐见地被追杀了。
他们面临的是一条有 N 个地点的路, 他们从 0 号地点出发, 要逃到 N 号地点去。每个地点的战斗都有一定的金币收入 Ai,也有一定的部队损失 Bi。
为了更好地逃生, Delfador 还弄到了一块传送宝石,这样一行人就能向后传送不超过 L 的距离。从一个地点传送到另一个地点时,Konrad 会选择路径上除起点外的地形指数 Ci 最大的地点进行战斗,地形指数相同时选择最靠后的。
作为优秀的领导者, Konrad 希望总金币收入与总部队损失的比值最大。
思路
如果没有长度(L)的限制,以及找(c)最大的地方打架的限制,那么这道题就是一个裸的(01)分数规划的问题。
有了这些限制后依然一样,先二分(mid)表示(frac{sum A_i}{sum B_i}geq mid),然后判断能否选出一些(i)满足上式。
那么我们要让(sum (A_i-mid imes B_i))大于零。
设(f[i])表示跳到点(i)时,(sum (A_j-mid imes B_j))的最大值,其中(j)是选择的落脚点。
那么先预处理出每一个点的影响区间([l_i,r_i]),意思是在([l_i,r_i])的点如果跳到点(i)后面,将会在(i)处打架。
这个可以用平衡树、线段树、(bit)、单调队列+二分等东西在(O(nlog n))的时间复杂度内求出来,具体方法留作思考(雾
那么显然有转移
[f[i]=max(f[j]+A_k-B_k imes mid)],(k)应该为((j,i])中(c)最大且尽量靠后的那一个。
如果(f[n]geq 0),那么(mid)就过小,否则过大。
代码
特别丑+调到自闭。
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=300010,Inf=1e9;
int n,m,a[N],b[N],c[N],d[N],L[N],R[N];
double f[N];
struct Segnode
{
int l,r,mn;
};
struct SegTree
{
Segnode tree[N*4];
void pushup(int x)
{
tree[x].mn=max(tree[x*2].mn,tree[x*2+1].mn);
}
void build(int x,int l,int r,int val)
{
tree[x].l=l; tree[x].r=r; tree[x].mn=val;
if (l==r) return;
int mid=(l+r)>>1;
build(x*2,l,mid,val);
build(x*2+1,mid+1,r,val);
}
int ask(int x,int l,int r)
{
if (tree[x].l==l && tree[x].r==r)
return tree[x].mn;
int mid=(tree[x].l+tree[x].r)>>1;
if (r<=mid) return ask(x*2,l,r);
if (l>mid) return ask(x*2+1,l,r);
return max(ask(x*2,l,mid),ask(x*2+1,mid+1,r));
}
void update(int x,int k,int val)
{
if (tree[x].l==k && tree[x].r==k)
{
tree[x].mn=val;
return;
}
int mid=(tree[x].l+tree[x].r)>>1;
if (k<=mid) update(x*2,k,val);
else update(x*2+1,k,val);
pushup(x);
}
}seg;
struct Segnode2
{
int l,r;
double maxn,f,k,lazy;
};
struct SegTree2
{
Segnode2 tree[N*4];
void pushup(int x)
{
tree[x].maxn=max(tree[x*2].maxn,tree[x*2+1].maxn);
tree[x].f=max(tree[x*2].f,tree[x*2+1].f);
}
void pushdown(int x)
{
if (tree[x].lazy)
{
tree[x*2].maxn=tree[x*2].f+tree[x].lazy;
tree[x*2+1].maxn=tree[x*2+1].f+tree[x].lazy;
tree[x*2].k=tree[x*2].lazy=tree[x].lazy;
tree[x*2+1].k=tree[x*2+1].lazy=tree[x].lazy;
tree[x].lazy=0;
}
}
void build(int x,int l,int r)
{
tree[x].l=l; tree[x].r=r; tree[x].lazy=0;
tree[x].maxn=tree[x].f=tree[x].k=-100000000000.0;
if (l==r) return;
int mid=(l+r)>>1;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
}
double ask(int x,int l,int r)
{
if (l>r) return -1000000000000.0;
if (tree[x].l==l && tree[x].r==r)
return tree[x].maxn;
pushdown(x);
int mid=(tree[x].l+tree[x].r)>>1;
if (r<=mid) return ask(x*2,l,r);
if (l>mid) return ask(x*2+1,l,r);
return max(ask(x*2,l,mid),ask(x*2+1,mid+1,r));
}
void updatef(int x,int k,double val)
{
if (tree[x].l==k && tree[x].r==k)
{
tree[x].f=val;
return;
}
int mid=(tree[x].l+tree[x].r)>>1;
if (k<=mid) updatef(x*2,k,val);
else updatef(x*2+1,k,val);
pushup(x);
}
void updatek(int x,int l,int r,double val)
{
if (tree[x].l==l && tree[x].r==r)
{
tree[x].k=tree[x].lazy=val;
tree[x].maxn=tree[x].f+tree[x].k;
return;
}
pushdown(x);
int mid=(tree[x].l+tree[x].r)>>1;
if (r<=mid) updatek(x*2,l,r,val);
else if (l>mid) updatek(x*2+1,l,r,val);
else updatek(x*2,l,mid,val),updatek(x*2+1,mid+1,r,val);
pushup(x);
}
}seg2;
bool check(double mid)
{
seg2.build(1,0,n);
seg2.updatef(1,0,0.0);
for (int i=1;i<=n;i++)
{
seg2.updatek(1,L[i],i-1,1.0*a[i]-1.0*b[i]*mid);
f[i]=seg2.ask(1,max(i-m,0),i-1);
seg2.updatef(1,i,f[i]);
}
return f[n]>=0.0;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%d%d%d",&a[i],&b[i],&c[i]);
d[i]=c[i];
}
sort(d+1,d+1+n);
int cnt=unique(d+1,d+1+n)-d-1;
for (int i=1;i<=n;i++)
c[i]=lower_bound(d+1,d+1+cnt,c[i])-d;
seg.build(1,1,cnt+1,0);
for (int i=1;i<=n;i++)
{
L[i]=max(max(0,i-m),seg.ask(1,c[i]+1,cnt+1));
seg.update(1,c[i],i);
}
double l=0.00001,r=1000000.0,mid;
while (r-l>0.0000000003)
{
mid=(l+r)/2.0;
if (check(mid)) l=mid;
else r=mid;
}
cnt=0;
for (;l>=10.0;cnt++) l/=10.0;
for (;l<=1.0;cnt--) l*=10.0;
printf("%0.9lfe",l);
if (cnt<0) printf("-");
else printf("+");
cnt=abs(cnt);
if (cnt<10) printf("00%d",cnt);
else if (cnt<100) printf("0%d",cnt);
else printf("%d",cnt);
return 0;
}
以上是关于GMOJ4017逃跑的主要内容,如果未能解决你的问题,请参考以下文章