2019牛客暑期多校训练营(第十场)J(斜率优化dp)

题目链接

题意

n n n 个木材,求制造 k k k 个木板浪费的木材的最小值,木材可以随意组合
制造木板浪费的木材:将 m m m 块木材连在一起,将所有的木材砍成一样的高度,砍掉的就是浪费量

思路

有分治优化,斜率优化, w q s wqs wqs 二分,我写的斜率优化 d p dp dp
先按高度从大到小排序
d p i , j dp_{i,j} dpi,j 表示前 i i i 个木材制成 k k k个木板的最小浪费量
s u m i sum_{i} sumi 表示前 i i i 个木材总面积
s u m w i sumw_{i} sumwi 表示前 i i i 个木材的宽度
d p i , j = d p k , j − 1 + s u m i − s u m k − h i ∗ ( s u m w i − s u m w k ) dp_{i,j} = dp_{k,j-1} + sum_{i} - sum_{k} - h_{i} * (sumw_{i} - sumw_{k}) dpi,j=dpk,j1+sumisumkhi(sumwisumwk)
由于 d p i , j dp_{i,j} dpi,j 只与 d p k , j − 1 dp_{k,j-1} dpk,j1 有关,因此只用记前一个状态就行,设当前状态为 s t a t e state state,则前一个状态为 1 − s t a t e 1 - state 1state
j < k < i j < k < i j<k<i k k k 点比 j j j 点更优,易得
d p k , 1 − s t a t e + s u m i − s u m k − h i ∗ ( s u m w i − s u m w k ) < = d p j , 1 − s t a t e + s u m i − s u m j − h i ∗ ( s u m w i − s u m w j ) dp_{k,1-state} + sum_{i} - sum_{k} - h_{i} * (sumw_{i} - sumw_{k}) <= dp_{j,1-state} + sum_{i} - sum_{j} - h_{i} * (sumw_{i} - sumw_{j}) dpk,1state+sumisumkhi(sumwisumwk)<=dpj,1state+sumisumjhi(sumwisumwj)
d p k , 1 − s t a t e − s u m k + d p j , 1 − s t a t e − s u m j s u m w k − s u m w j < = − h i \frac{dp_{k,1-state} - sum_{k} + dp_{j,1-state} - sum_{j}}{sumw_{k} - sumw_{j}} <= - h_{i} sumwksumwjdpk,1statesumk+dpj,1statesumj<=hi
y i = d p k , 1 − s t a t e − s u m k y_{i} = dp_{k,1-state} - sum_{k} yi=dpk,1statesumk x i = s u m w k x_{i} = sumw_{k} xi=sumwk y k − y j x k − x j < = − h i \frac{y_{k} -y_{j}}{x_{k} - x_{j}} <= - h_{i} xkxjykyj<=hi
说明如果 k k k 为解, j , k , i j,k,i j,k,i 应该是上凸的,则解集是下凸的,用一个单调队列维护解集

#include 
#include 
#include 
#define mem(x,y) memset(x,y,sizeof x)
#define fo(i,s,t) for(int i=s;i<=t;i++)
#define cl1(x,y,n) fo(c1_i,0,n-1) x[c1_i]=y
#define cl2(x,y,n,m) fo(c2_i,0,n-1) fo(c2_j,0,m-1) x[c2_i][c2_j]=y
#define inf (~0U>>2)
#define inff (long long)(inf<<1)*(long long)(inf<<1)
using namespace std;
const int maxn=5e3+10;
const int maxm=2e3+10;
const int mod=1e9+7;
int n,k,q[maxn],state=1;
long long sum[maxn],sumw[maxn],dp[maxn][2];
struct node{long long w,h;}a[maxn];
bool cmp(node _x,node _y)
{
    return _x.h>_y.h;
}
///dp[i][j]=dp[k][j-1]+sum[i]-sum[k]-a[i].h*(sumw[i]-sumw[k])
long long x(int i)
{
    return sumw[i];
}
long long y(int i)
{
    return  dp[i][1-state]-sum[i];
}
double slope(int i,int j)
{
    return (y(j)-y(i))*1.0/(x(j)-x(i));
}
int main()
{
    scanf("%d%d",&n,&k);
    fo(i,1,n) scanf("%lld%lld",&a[i].w,&a[i].h);
    sort(a+1,a+n+1,cmp);
    sum[0]=sumw[0]=0;
    fo(i,1,n)
    {
        sum[i]=sum[i-1]+a[i].w*a[i].h;
        sumw[i]=sumw[i-1]+a[i].w;
        dp[i][1]=sum[i]-sumw[i]*a[i].h;
    }
    fo(j,2,k)
    {
        int l=1,r=1;
        q[1]=0;
        state=1-state;
        fo(i,1,n)
        {
            /**不卡精度可以用这个
            while(l=slope(q[r],i))
                r--;
            q[++r]=i;*/
            while(l=__int128_t(y(i)-y(q[r]))*__int128_t(x(q[r])-x(q[r-1])))
                r--;
            q[++r]=i;
        }
    }
    printf("%lld\n",dp[n][k%2]);
    return 0;
}

你可能感兴趣的:(2019牛客暑期多校训练营(第十场)J(斜率优化dp))