• Estimation


    Estimation

    给出一个长度为n序列({a_i}),将其划分成连续的K段,对于其中一段([l,r]),设其中位数为m,定义其权值为(sum_{i=l}^r|m-a_i|),求最小的权值之和,(nleq 2000,Kleq 25)

    显然设(f[i][j])表示前i个数划分成j段的的最小权值和,设(m(i,j))(isim j)的作为一段的权值,所以有

    [f[i][j]=min_{0leq k<i}{f[k][j-1]+m(k+1,i)} ]

    边界:(f[0][0]=0),其余无限大

    答案:(f[n][K])

    注意到时间复杂度(2000^2 imes 25=10^8),为一亿,可以险过,关键在于快速求二元函数m,而求m需要解决的是动态维护一段序列中中间大的数,显然中位数的位置是递增的,可以考虑双堆堆顶优化,不难得知对于序列(b_1,b_2,...,b_p)而言设其中位数为(b_q),于是有权值为

    [sum_{i=1}^p|b_i-b_q|=|b_p-b_q|+...+|b_q-b_q|+...+|b_q-b_1|= ]

    [=b_p-b_q+..+b_q-b_q+...+b_q-b_1=(b_p+...+b_{q+1})-(b_q+...+b_1)+qb_q-(p-q)b_q= ]

    [sum_{i=q+1}^pb_i-sum_{i=1}^qb_i+(2q-p)b_q ]

    于是对于权值,我们只要维护这样一个式子即可,步骤如下

    1. 枚举左端点i,设大根堆为H,小根堆为E
    2. 初始化(m(i,i)=0,k=-a_i),H加入(a_i)
    3. 枚举右端点j
    4. 如果(a_jleq H.top()),那么(E.push(H.top()),H.pop(),k+=E.top() imes 2,H.push(a_j),k-=a_j)
    5. 否则(E.push(a_j),k+=a_j)
    6. 如果(i-j+1)为偶数的话,那么(H.push(E.top()),E.pop(),k-=H.top() imes 2)
    7. 计入答案(m(i,j)=k+(2q-p) imes H.top())

    参考代码:

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <functional>
    #include <cstring>
    #define il inline
    #define ri register
    #define intmax 0x7fffffff
    using namespace std;
    int a[2001],m[2001][2001],dp[2001][26];
    priority_queue<int,vector<int>,less<int> >H;
    priority_queue<int,vector<int>,greater<int> >E;
    il void read(int&);
    int main(){
        int n,K;
        while(read(n),read(K),n&&K){
            for(int i(1);i<=n;++i)read(a[i]);
            for(int i(1),j,k;i<=n;++i){
                while(H.size())H.pop();
                while(E.size())E.pop();
                H.push(a[i]),k=-a[i];
                for(j=i+1;j<=n;++j){
                    if(a[j]<=H.top())
                        E.push(H.top()),H.pop(),H.push(a[j]),
                            k-=a[j],k+=E.top()<<1;
                    else E.push(a[j]),k+=a[j];
                    if((j-i+1)&1)k-=E.top()<<1,H.push(E.top()),E.pop();
                    m[i][j]=k+H.top()*((H.size()<<1)-(j-i+1));
                }
            }memset(dp,2,sizeof(dp)),dp[0][0]=0;
            for(int i,j(1),k;j<=K;++j)
                for(i=j;i<=n;++i)
                    for(k=0;k<i;++k)
                        if(dp[i][j]>dp[k][j-1]+m[k+1][i])
                            dp[i][j]=dp[k][j-1]+m[k+1][i];
            printf("%d
    ",dp[n][K]);
        }
        return 0;
    }
    il void read(int &x){
        x&=0;ri char c;while(c=getchar(),c==' '||c=='
    '||c=='
    ');
        ri bool check(false);if(c=='-')check|=true,c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        if(check)x=-x;
    }
    
  • 相关阅读:
    DBUtils温习2
    DBUtils温习1
    C3P0连接池温习1
    JDBC复习2
    JDBC复习1
    Spring的AOP基于AspectJ的注解方式开发3
    Spring的AOP基于AspectJ的注解方式开发2
    Spring的AOP基于AspectJ的注解方式开发1
    高血压认知3
    pandas cookbook
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/11031255.html
Copyright © 2020-2023  润新知