2019牛客暑期多校訓練營(第十場)J Wood Processing 斜率DP or 分治DP

題意:

n塊矩形,問你合併成K塊,切掉的面積最小是多少

思路1:斜率DP

首先按照高度從小到大排序

F[I][J]表示前i塊矩形,劃分成J塊的最小代價。則

F[I][J]=min(F[I][J],F[K][J-1]+W(K+1,I))

W(i,j)表示把i到j這些合併一起的代價,sum[i]-sum[k]- h[k+1]*(sumw[i]-sumw[k]).

最後整理可得如下形式的斜率式:F[I]+A[I]*A[J]=F[J]+C[J](b+kx=y)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=b;i>=a;i--)
using namespace std;
#define ll long long
ll rd()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
 
struct node{
    ll w,h;
}p[50100],qq[50100];
ll sumw[50100],sum[50100];
const int N=50100;
int now,pre;
ll s[N],f[N][2],n,x,L,j,q[N],tail,head,k;
inline double X(ll i) {return p[i+1].h;}
inline double Y(ll i) {return f[i][pre]-sum[i]+p[i+1].h*sumw[i];}
inline double slope(ll i,ll j){return (Y(j)-Y(i))/(X(j)-X(i));}
 
bool cmp(node a,node b)
{
    return a.h<b.h;
}
void init()
{
    memset(sumw,0,sizeof(sumw));
    memset(sum,0,sizeof(sum));
    n=rd();k=rd();
    rep(i,1,n)
    {
        ll x,y;
        x=rd();y=rd();
        qq[i]={x,y};
    }
    sort(qq+1,qq+1+n,cmp);
    int tot=0;
    rep(i,1,n)
    if(qq[i].h==p[tot].h)
    {
        p[tot].w+=qq[i].w;
    }
    else{
        tot++;
        p[tot].w=qq[i].w;
        p[tot].h=qq[i].h;
    }
    n=tot;
    rep(i,1,n)
    {
        sumw[i]=sumw[i-1]+p[i].w;
    }
    rep(i,1,n)
    {
        sum[i]=sum[i-1]+p[i].w*p[i].h;
    }
    head=tail=1;q[1]=0;
}
int main()
{
    memset(f,0,sizeof(f));
    init();
    now=0;pre=1;
     
    rep(i,1,n) f[i][0]=1e18;
    rep(o,1,k)
    {
        head=tail=1;q[1]=0;
        //f[][0]=f[0][0]=0;
        now=!now;pre=!pre;
        rep(i,1,n)
        {
            while(head<tail && slope(q[head],q[head+1])<sumw[i]) head++;
            //printf("%.3lf\n",slope(q[1],q[2]));
            j=q[head];
            //printf("j:=%d %d %d\n",j,tail,head);
            f[i][now]=f[j][pre]+(sum[i]-sum[j])-p[j+1].h*sumw[i]+p[j+1].h*sumw[j];
            //f[i]=f[j]+(s[i]-s[j]-L)*(s[i]-s[j]-L);
            while(head<tail&& slope(q[tail-1],q[tail])>slope(q[tail],i)) tail--;
            q[++tail]=i;   
        }
//      rep(i,1,n) printf("%d ",f[i][now]);
//      printf("\n");
    }
    printf("%lld\n",f[n][now]);
}

思路2:分治DP

打表可得,F[I]是從J轉移過來的,F[i-1]是從K轉移過來的,J始終>=K,則可用分治DP。

 

思路3:wqs帶權二分(待補)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章