• 2019牛客暑期多校第十场 J.Wood Processing


    2019牛客暑期多校第十场 J.Wood Processing

    题意:

    (nleq5000)个 宽度为(w_i),高为(h_i) 的 木块,要求分成(k)组,对于每组内的所有木块,高度都变为组内最低木块的高度,宽度保持不变,求变化的最小面积。

    思路:

    先按照高度从大到小排个序。

    其实就相当于将这些序列cut成k份,每份有一个代价,要求总代价最小。

    每一份中的代价取决于什么呢?

    • 这一份木板中最矮的那一个的高度。
    • (其他木板的高度与最矮的高度之差)*其他木板的宽度。

    知道这些之后,就可以开始(dp)了。

    这时候可以设(f(i,j))表示考虑到第(i)块木板,切成了(j)份的最小代价是多少。

    但是这样不太好,因为每一份中木板的高度不尽相同,所以势必让转移方程变复杂。

    所以换一个思路,设(f(i,j))表示考虑到第(i)块木板,切了(j)份之后最大的面积是多少。

    [f(i,j)=max(f(k,j-1)+(sW(i)-sW(k)*h(i)) ]

    其中(0leq k< i)(sW)表示宽度的前缀和。此时答案为(tot-f(n,k)),其中(tot)表示木板总面积。

    由于需要枚举(i,j,k),时间复杂度(O(n^3)),无法通过。

    展开上式

    [f(i,j)=sW(i)h(i)+max{f(k,j-1)-sW(k)*h(i)} ]

    去掉(max:)

    [f(i,j)=sW(i)h(i)+f(k,j-1)-sW(k)*h(i) ]

    [f(k,j-1)=sW(k)*h(i)+[f(i,j)-sW(i)h(i)] ]

    这样的话就变成斜率(dp)的形式了。

    我们发现转移方程成了以(sW(k))为自变量,(f(k,j-1))为因变量,(h(i))为斜率,(f(i,j)-sW(i)h(i))为截距的直线。

    当截距最大时,(f(i,j))取到最大。

    所以用单调队列维护一个上凸壳。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 5000+10;
    typedef long long ll;
    struct Node{
        ll w, h;
    }a[maxn];
    bool cmp(Node a, Node b){
        return a.h > b.h;
    }
    
    int n, k;
    int q[maxn];
    ll sum[maxn];
    ll f[maxn][maxn];
    ll area;
    
    long double slope(int x,int y,int p){
        return (long double)1.0*(f[x][p-1]-f[y][p-1])/(sum[x]-sum[y]);
    }
    
    int main()
    {
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; i++)
            scanf("%lld%lld", &a[i].w, &a[i].h);
        sort(a+1, a+1+n, cmp);
        for(int i = 1; i <= n; i++)
        {
            sum[i] = sum[i-1]+a[i].w;
            area += a[i].h*a[i].w;
        }
    
    
        int hh, tt;
        //队列中数据单调递减
        for(int j = 1; j <= k; j++)
        {
            hh = 1, tt = 1;
            for(int i = 1; i <= n; i++)
            {
                while(hh < tt && slope(q[hh],q[hh+1],j) >= a[i].h) hh++;
                int t = q[hh];
                f[i][j] = f[t][j-1]+(sum[i]-sum[t])*a[i].h;
                while(hh < tt && slope(q[tt],q[tt-1],j) <= slope(q[tt],i,j)) tt--;
                q[++tt] = i;
            }
        }
        cout << (area-f[n][k]) << endl;
        return 0;
    }
    
    
  • 相关阅读:
    How to Compile Java DBus
    BZOJ 2783 JLOI 2012 树 乘+二分法
    Robotium原则的实施源代码分析
    基本的负载均衡算法
    人大、上财、复旦、上交四校2013年应届金融硕士就业去向
    2014届上财金融硕士就业情况
    三跨),总分420+
    复旦金融专硕和上财金融专硕
    一个三跨考生三战上海财经大学金融硕士的考研经验
    董某某
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/12325334.html
Copyright © 2020-2023  润新知