zoukankan      html  css  js  c++  java
  • 【BZOJ4897】成绩单(THUSC2016)-玄幻区间DP

    测试地址:成绩单
    做法:本题需要用到区间DP。
    容易想到每次取的都是一个子序列。直觉上想到的一个状态定义是,令f(i,j)为删掉区间[i,j]中所有数的最小代价,但我们发现这没法转移,又注意到转移和所取的子序列中最大数和最小数有关,那么便有了如下状态定义和状态转移方程:
    f(i,j,l,r)为删掉区间[i,j]中的一部分数,使得剩下的数都在[l,r]范围内的最小代价,g(i,j)为删掉区间[i,j]中所有数的代价,则有:
    f(i,j,l,r)=min(g(tl,tr),f(i,k,l,r)+f(k+1,j,l,r)(ik<j))
    其中tl,tr为区间[l,r]中从左边/右边开始数第一个不在[l,r]内的数的位置。这个方程通过一种玄幻的方式枚举了所有可能是最优的方案,可以感性理解一下……
    然后我们有:
    g(i,j)=min(f(i,j,l,r)+a+b(rl)2)
    这个方程就很显然了。那么我们把所有数离散化后做DP,就可以解决这一题了,时间复杂度为O(n5)
    (这题真的好难啊……为什么还有dalao说是DP入门题啊……可能是国家队入门吧)
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll inf=1000000000ll*1000000000ll;
    int n,now[55];
    ll a,b,pos[55],f[55][55][55][55],g[55][55];
    struct forsort
    {
        int id;
        ll val;
    }F[100];
    
    bool cmp(forsort a,forsort b)
    {
        return a.val<b.val;
    }
    
    int main()
    {
        scanf("%d%lld%lld",&n,&a,&b);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&F[i].val);
            F[i].id=i;
        }
    
        sort(F+1,F+n+1,cmp);
        int tot=0;
        for(int i=1;i<=n;i++)
        {
            if (i==1||F[i].val!=F[i-1].val) pos[++tot]=F[i].val;
            now[F[i].id]=tot;
        }
    
        for(int i=1;i<=n;i++)
        {
            g[i][i]=a;
            for(int l=1;l<=tot;l++)
                for(int r=l;r<=tot;r++)
                {
                    if (now[i]>=l&&now[i]<=r) f[i][i][l][r]=0;
                    else f[i][i][l][r]=a;
                }
        }
        for(int len=2;len<=n;len++)
            for(int i=1;i+len-1<=n;i++)
            {
                int j=i+len-1,maxv=0,minv=tot+1;
                for(int x=i;x<=j;x++)
                    maxv=max(maxv,now[x]),minv=min(minv,now[x]);
                g[i][j]=a+b*(pos[maxv]-pos[minv])*(pos[maxv]-pos[minv]);
                for(int l=1;l<=tot;l++)
                    for(int r=l;r<=tot;r++)
                    {
                        int tl=i-1,tr=j+1;
                        for(int k=i;k<=j;k++)
                        {
                            if (now[k]>=l&&now[k]<=r) tl=k;
                            else break;
                        }
                        for(int k=j;k>=i;k--)
                        {
                            if (now[k]>=l&&now[k]<=r) tr=k;
                            else break;
                        }
                        if (tl>=tr) f[i][j][l][r]=0;
                        else f[i][j][l][r]=g[tl+1][tr-1];
                        for(int k=i;k<j;k++)
                            f[i][j][l][r]=min(f[i][j][l][r],f[i][k][l][r]+f[k+1][j][l][r]);
                    }
                for(int l=1;l<=tot;l++)
                    for(int r=l;r<=tot;r++)
                        g[i][j]=min(g[i][j],f[i][j][l][r]+a+b*(pos[r]-pos[l])*(pos[r]-pos[l]));
            }
        printf("%lld",g[1][n]);
    
        return 0;
    }
  • 相关阅读:
    JS中prototype属性解释及常用方法
    HTML5 组件Canvas实现图像灰度化
    洛谷.5284.[十二省联考2019]字符串问题(后缀自动机 拓扑 DP)
    洛谷.5290.[十二省联考2019]春节十二响(贪心)
    洛谷.5283.[十二省联考2019]异或粽子(可持久化Trie 堆)
    SDOI2019 省选前模板整理
    完美理论(最大权闭合子图)
    BZOJ.3566.[SHOI2014]概率充电器(概率DP 树形DP)
    BZOJ.2616.SPOJ PERIODNI(笛卡尔树 树形DP)
    4.2模拟赛 wormhole(期望DP Dijkstra)
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793358.html
Copyright © 2011-2022 走看看