[HDU 4261] Estimation

[题目链接]

         http://acm.hdu.edu.cn/showproblem.php?pid=4261

[算法]

        首先,有一个结论 :

        | a[1] - k | + | a[2] - k | + ... + | a[n] - k | 当k取(a[1],a[2], ... , a[n])的中位数时,式子的值最小

        考虑动态维护中位数

        我们用一个大根堆和一个小根堆,大根堆中存放前[1..N/2](向上取整)小的数,小根堆中存放[N/2 + 1,N]小的数,还需维护两个变量s1和s2,分别为小根堆中所有数的和和大根堆中所有数的和

        这样,我们就可以预处理出每一段的最小值

        然后,我们用f[i][j]表示前i个数分成j段取得的最小值,有状态转移方程 :

        f[i][j]  = min{ f[k][j - 1] + middle( k + 1,i) ) (其中,middle(k + 1,i)表示[k + 1,i]中每个数与中位数的差值和)

        答案即为f[n][k]

[代码]

          

#include<bits/stdc++.h>
using namespace std;
#define MAXN 2010
#define MAXK 30
const int INF = 2e9;

int i,j,k,s1,s2,x,y,n,m,middle;
int a[MAXN],sum[MAXN][MAXN];
int f[MAXN][MAXK];

struct Sheap
{
        int tot;
        int a[MAXN];
        inline void clear()
        {
                tot = 0;
        }
        inline void up(int now)
        {
                if (now == 1) return;
                int fa = now >> 1;
                if (a[now] < a[fa])
                {    
                        swap(a[now],a[fa]);
                        up(fa);
                }
        }
        inline void down(int now)
        {
                int son = now << 1;
                if (son > tot) return;
                if (son + 1 <= tot && a[son + 1] < a[son]) son++;
                if (a[son] < a[now])
                {
                        swap(a[son],a[now]);
                        down(son);
                }
        }
        inline void insert(int x)
        {
                a[++tot] = x;
                up(tot);
        }
        inline void del()
        {
                swap(a[1],a[tot]);
                tot--;
                down(1);
        }
        inline int getroot()
        {
                return a[1];
        }
} S;
struct Bheap
{
        int tot;
        int a[MAXN];
        inline void clear()
        {
                tot = 0;        
        }            
        inline void up(int now)
        {
                if (now == 1) return;
                int fa = now >> 1;
                if (a[now] > a[fa])
                {
                        swap(a[now],a[fa]);
                        up(fa);
                }
        }
        inline void down(int now)
        {
                int son = now << 1;
                if (son > tot) return;
                if (son + 1 <= tot && a[son + 1] > a[son]) son++;
                if (a[son] > a[now])
                {
                        swap(a[now],a[son]);
                        down(son);
                }
        }
        inline void insert(int x)
        {
                a[++tot] = x;
                up(tot);
        }
        inline void del()
        {
                swap(a[1],a[tot]);
                tot--;
                down(1);
        }
        inline int getroot()
        {
                return a[1];
        }
} B;

int main() 
{
        
        while (scanf("%d%d",&n,&m) && (n || m))
        {
                for (i = 1; i <= n; i++) scanf("%d",&a[i]);
                for (i = 1; i <= n; i++)
                {
                        B.clear();
                        S.clear();
                        sum[i][i] = 0;
                        B.insert(a[i]);
                        s1 = a[i];
                        s2 = 0;
                        for (j = i + 1; j <= n; j++)
                        {
                                if (B.tot <= (j - i) / 2) 
                                {
                                        B.insert(a[j]);
                                        s1 += a[j];
                                } else 
                                {
                                        S.insert(a[j]);
                                        s2 += a[j];
                                }
                                x = B.getroot();
                                y = S.getroot();
                                if (x > y)
                                {
                                        B.del();
                                        s1 -= x;
                                        S.del();
                                        s2 -= y;
                                        S.insert(x);
                                        s2 += x;
                                        B.insert(y);    
                                        s1 += y;    
                                } 
                                middle = B.getroot();
                                sum[i][j]    = middle * B.tot - s1 + s2 - middle * S.tot;
                        }        
                }        
                for (i = 1; i <= n; i++)
                {
                        for (j = 1; j <= m; j++)
                        {
                                f[i][j] = INF;
                        }
                }
                for (i = 1; i <= n; i++) f[i][1] = sum[1][i];
                for (i = 1; i <= n; i++)
                {
                        for (j = 2; j <= m; j++)
                        {
                                for (k = i - 1; k >= 1; k--)
                                {
                                        f[i][j] = min(f[i][j],f[k][j - 1] + sum[k + 1][i]);
                                }
                        }
                }
                printf("%d\n",f[n][m]);
        }
        
        return 0;
    
}

猜你喜欢

转载自www.cnblogs.com/evenbao/p/9357093.html