zoukankan      html  css  js  c++  java
  • Gym

    题意:有一个厨师,他买菜-做菜-买菜-做菜....-做菜,一共有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
    ",dp[N]);
        return 0;
    }
  • 相关阅读:
    SVG前戏—让你的View多姿多彩
    分享几个Android很强势的的开源框架
    终于,我还是下决心学Java后台了
    金9银10,分享几个重要的Android面试题
    django-多表操作2
    python基础-文件操作
    django-单表操作
    django-多表操作
    django-模板层基础2
    djano-模板层基础知识
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10353561.html
Copyright © 2011-2022 走看看