zoukankan      html  css  js  c++  java
  • [2020多校联考]甲虫

    [BalticOI 2009]甲虫

    Solution

    比较套路的区间dp,先按坐标排序,再找出零点所在位置,记为 (pos)。设状态 (dp[i][j][0/1]) 表示取完区间 ([i,j]) 的所有水滴且最后位置在左边/右边的最大收益,但时间不好算,可以再开一个 (t[i][j][0/1]) 来记录最优解转移到 (dp[i][j][0/1]) 时的时间,那么转移就很显然了。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    #define N 307
    #define ll long long
     
    ll dp[N][N][2],t[N][N][2],a[N];
    int n,m;
    int main(){
        freopen("data.in","r",stdin);
        freopen("user.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
        sort(a+1,a+1+n+1);
        int pos;
        for(int i=1;i<=n+1;i++)
            if(!a[i]){pos=i;break;}
        memset(dp,-63,sizeof(dp));
        dp[pos][pos][0]=dp[pos][pos][1]=0;
        t[pos][pos][0]=t[pos][pos][1]=m;
        ll ans=0;
        for(int l=2;l<=n+1;l++)
            for(int i=1,j=i+l-1;j<=n+1;i++,j++){
                if(dp[i+1][j][0]+t[i+1][j][0]-(a[i+1]-a[i])>dp[i][j][0]){
                    dp[i][j][0]=dp[i+1][j][0]+t[i+1][j][0]-(a[i+1]-a[i]);
                    t[i][j][0]=t[i+1][j][0]-(a[i+1]-a[i]);
                }
                if(dp[i+1][j][1]+t[i+1][j][1]-(a[j]-a[i])>dp[i][j][0]){
                    dp[i][j][0]=dp[i+1][j][1]+t[i+1][j][1]-(a[j]-a[i]);
                    t[i][j][0]=t[i+1][j][1]-(a[j]-a[i]);
                }
                if(dp[i][j-1][1]+t[i][j-1][1]-(a[j]-a[j-1])>dp[i][j][1]){
                    dp[i][j][1]=dp[i][j-1][1]+t[i][j-1][1]-(a[j]-a[j-1]);
                    t[i][j][1]=t[i][j-1][1]-(a[j]-a[j-1]);
                }
                if(dp[i][j-1][0]+t[i][j-1][0]-(a[j]-a[i])>dp[i][j][1]){
                    dp[i][j][1]=dp[i][j-1][0]+t[i][j-1][0]-(a[j]-a[i]);
                    t[i][j][1]=t[i][j-1][0]-(a[j]-a[i]);
                }
                ans=max(ans,max(dp[i][j][0],dp[i][j][1]));
            }
        printf("%lld",ans);
    }
    /*
    3 15
    6 -3 1
    */
    

    然后你就可以得到 (76) 分的高分。(这是我没有想到的)

    上述做法的问题在于虽然 (dp[i][j][0/1]) 在当前是最优的,但是 (t[i][j][0/1]) 可能已经被减得很小了,甚至是负的,对后面的转移不利(所以这直接就是个假作法)。转换思路,考虑费用提前算,枚举当前必选的水滴的个数,然后考虑进行dp。状态 (dp[i][j][0/1]) 变为在选完区间 ([i,j]) 且最后位置在左边/右边,能使得到水滴丢失的最少水分是多少,这个状态的实质是让上文的 (t) 尽量大,而对后面的状态产生正影响,那么这个算法的正确性就显然了。转移也很显然。那么对于不同的选取个数 (lim) ,分别进行一次dp后,答案就是

    [lim imes m-min limits_{1leq lleq l+lim-1leq n}{dp[l][l+lim-1]} ]

    那么总的答案就是

    [max limits_{1leq lim leq n} {lim imes m-min limits_{1leq lleq l+lim-1leq n}{dp[l][l+lim-1]}} ]

    复杂度 (O(n^3))

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    #define N 307
    #define ll long long
    
    int n,m,pos=0;
    ll dp[N][N][2],a[N];
    
    inline ll calc(int lim){
        memset(dp,127,sizeof(dp));
        dp[pos][pos][0]=dp[pos][pos][1]=0;
        for(int l=2;l<=lim;l++)
            for(int i=1,j=i+l-1;j<=n;i++,j++){
                dp[i][j][0]=min(dp[i][j][0],min(dp[i+1][j][0]+(a[i+1]-a[i])*(lim-l+1),dp[i+1][j][1]+(a[j]-a[i])*(lim-l+1)));
                dp[i][j][1]=min(dp[i][j][1],min(dp[i][j-1][1]+(a[j]-a[j-1])*(lim-l+1),dp[i][j-1][0]+(a[j]-a[i])*(lim-l+1)));
            }
        ll ret=(1LL<<60);
        for(int i=1,j=i+lim-1;j<=n;i++,j++)
            ret=min(ret,min(dp[i][j][0],dp[i][j][1]));
    //    printf("%lld
    ",ret);
        return ret;
    }
    
    int main(){
    //    freopen("beetle.in","r",stdin);
    //    freopen("beetle.out","w",stdout);
        scanf("%d%d",&n,&m);
        bool tag=0;
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]),tag|=(!a[i]);
        if(!tag) n++;
        sort(a+1,a+1+n);
        for(int i=1;i<=n;i++)
            if(!a[i]){pos=i;break;}
        ll ans=-1;
        for(int i=1;i<=n;i++)
            ans=max(ans,i*m-calc(i)-(!tag? m:0));
        printf("%lld",ans);
    }
    /*
    3 15
    6 -3 1
    */
    

    Tips

    原来的所有坐标中可能有 (0),也可能没有。这会对答案产生影响,但简单讨论一下就可以了。

  • 相关阅读:
    jquery文件上传控件 Uploadify
    【jQuery】uploadify,实际开发案例【选择完文件点击上传才上传】
    StarUML2 建模工具全平台破解及license验证简要分析
    Error:Failed to resolve: com.afollestad:material-dialogs:
    Android studio Github 断开连接
    Crashlytics Android 异常报告统计管理
    Android Studio集成crashlytics后无法编译的问题
    Android studio启动后卡在refreshing gradle project
    Android项目源码分享
    Android开发案例
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/14064082.html
Copyright © 2011-2022 走看看