• 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;
    }
    
    
  • 相关阅读:
    316 Remove Duplicate Letters 去除重复字母
    315 Count of Smaller Numbers After Self 计算右侧小于当前元素的个数
    313 Super Ugly Number 超级丑数
    312 Burst Balloons 戳气球
    309 Best Time to Buy and Sell Stock with Cooldown 买股票的最佳时间含冷冻期
    Java 类成员的初始化顺序
    JavaScript 全局
    HTML字符实体
    Java中的toString()方法
    JavaScript 弹窗
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/12325334.html
Copyright © 2020-2023  润新知