Live2d Test Env

Gym - 101806R :Recipe(分治+斜率优化)

题意:有一个厨师,他买菜-做菜-买菜-做菜....-做菜,一共有N天,他的冰箱里只能有一个菜,在他做菜的第二天才会买菜,如果菜不做,放在冰箱里,每天新鲜程度会下降1。 第一天也会买菜,第i天的菜新鲜程度的Fi,厨艺是Ci,(厨艺会增长),要求这一天做的菜的新鲜长度大于等于Li。

思路:即dpi=max dp[j]+[F[j+1]-(i-(j+1))]*Ci (满足Li>=F[j+1]-(i-j-1)); 表示成b=y+kx的可以求最大值,表示成b=y-kx的可以求最小值。

由于k=Ci是单增的,所以想到斜率优化,可以把原方程化为:dp i=max dpj +[F[j+1]+(j+1)]*Ci - i*Ci  满足(Li+i>=F[j+1]+j+1);

而由于有括号里的限制,我们不能简单的斜率优化DP。 而考虑分治,分治的情况下,我们可以把Mid左边的按照Fi+i排序,右边的按照Li+i排序,如果满足括号条件,则把左边加入凸包, 右边更新答案。 这个时候由于不是按下标插入,所以x不是单调的,所以我们要在凸包上二分答案。

#include<bits/stdc++.h>
#define pii pair<ll,int>
#define mp make_pair
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=300010;
const int inf=1e9;
ll dp[maxn],F[maxn],C[maxn],L[maxn];
pii a[maxn],b[maxn]; int q[maxn],top;
ll getans(int p,int k)
{
    return dp[k]+C[p]*F[k+1]-C[p]*p;
}
void update(int p)
{
    if(top==0) return;int L=1,R=top-1,Mid;
    dp[p]=max(dp[p],getans(p,q[top]));
    while(L<=R){
        Mid=(L+R)>>1;
        ll tmp1=getans(p,q[Mid]),tmp2=getans(p,q[Mid+1]);
        if(tmp1>tmp2) R=Mid-1,dp[p]=max(dp[p],tmp1);
        else L=Mid+1,dp[p]=max(dp[p],tmp2);
    }
}
bool check(int p){
    return (dp[p]-dp[q[top]])*(F[p+1]-F[q[top-1]+1])<=
     (dp[p]-dp[q[top-1]])*(F[p+1]-F[q[top]+1]);
}
void add(int p)
{
    if(dp[p]==-inf) return ;
    if(top>0&&F[p+1]==F[q[top]+1]&&dp[p]>dp[q[top]]) top--;
    while(top>1&&check(p)) top--;
    q[++top]=p;
}
void solve(int Le,int Ri)
{
    if(Le==Ri) return ;
    int Mid=(Le+Ri)>>1;
    solve(Le,Mid);
    int tot1=0,tot2=0; top=0;
    rep(i,Le,Mid) a[++tot1]=mp(F[i+1],i);
    rep(i,Mid+1,Ri) b[++tot2]=mp(L[i],i);
    sort(a+1,a+tot1+1); sort(b+1,b+tot2+1);
    reverse(a+1,a+tot1+1); reverse(b+1,b+tot2+1);
    for(int i=1,j=1;i<=tot2;i++){
       while(j<=tot1&&b[i].first<=a[j].first){
           add(a[j].second); j++;
       }
       update(b[i].second);
    }
    solve(Mid+1,Ri);
}
int main()
{
    int N; scanf("%d",&N);
    rep(i,1,N) scanf("%lld",&F[i]),F[i]+=i;
    rep(i,1,N) scanf("%lld",&C[i]);
    rep(i,1,N) scanf("%lld",&L[i]),L[i]+=i;
    rep(i,1,N) dp[i]=-inf;
    solve(0,N);
    if(dp[N]==-inf) puts("Impossible");
    else printf("%lld\n",dp[N]);
    return 0;
}

 

posted @ 2019-02-06 11:28  nimphy  阅读(293)  评论(0编辑  收藏  举报