#0/1分数规划,单调队列,dp#JZOJ 4017 逃跑 From 2020.02.07【NOIP提高组】模拟A 组

题目

一条有\(N\)个地点的路, 他们从0号地点出发, 要逃到\(N\)号地点去。
每个地点的战斗都有一定的金币收入\(Ai\),也有一定的部队损失\(Bi\)
一行人就能向后传送不超过\(L\)的距离。从一个地点传送到另一个地点时,
会选择路径上除起点外的地形指数\(Ci\)最大的地点进行战斗,地形指数相同时选择最靠后的。
希望总金币收入与总部队损失的比值最大。


分析

一眼望去,这不是0/1分数规划题吗……
未完待续


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=30011; int n,lo,ep,head,tail;
double a[N],b[N],c[N],dp[N];
struct rec{double dp,z; int c,lst,nxt,rk;}q[N];
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline double max(double a,double b){return a>b?a:b;}
inline bool check(double erf){
    q[head=tail=1]=(rec){0,0,0,0,0,0};
    for (rr int i=1;i<=n;++i){
        rr double z=a[i]-b[i]*erf; dp[i]=-1e15;
        for (;q[head].rk+lo<i;++head)
            if (q[head].nxt!=head+1)
                q[head+1].nxt=q[head].nxt;
        rr int P=head,p,Lst;
        for (rr int j=tail;j>=head;--j)
        if (q[j].c<=c[i]) q[j].c=c[i],q[j].z=z;
            else {P=j+1; break;}
        Lst=q[P].lst,q[P].lst=0,q[P].nxt=0,p=P;
        for (rr int st=P+1;st<=tail;++st){
            q[st].lst=q[st].nxt=0,q[++p]=q[st];
            for (;q[p].dp>=q[p-1].dp&&p>P;q[p-1]=q[p],--p);
        }
        tail=p,q[P].lst=Lst,q[Lst].nxt=P;
        for (rr int j=head;j;j=q[j].nxt) dp[i]=max(dp[i],q[j].dp+q[j].z);
        q[++tail]=(rec){dp[i],0,0,tail-1,0,i},q[P].lst=tail,q[tail].lst=P;
    }
    return dp[n]>=0;
}
signed main(){
    n=iut(),lo=iut();
    for (rr int i=1;i<=n;++i) a[i]=iut(),b[i]=iut(),c[i]=iut();
    rr double l=0,r=1000000;
    for (rr int i=1;i<=100;++i){
        rr double mid=(l+r)/2;
        if (check(mid)) l=mid;
            else r=mid;
    }
    while (l>10) ++ep,l/=10;
    while (l<1) --ep,l*=10; 
    printf("%.9lf",l);
    if (ep<0) printf("e-00%d",-ep);
        else printf("e+00%d",ep);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Spare-No-Effort/p/12286884.html