【斜率优化】 HDU 3669 Cross the Wall

通道

题意:给你n个矩形,长宽已知,求用不超过k个大矩形包含所有给定矩形,使得大矩形总面积和最小

思路:dp[i][j]表示前i个用j个大矩形的最少面积 ,则dp[i][j]=Min(dp[k][j-1]+w[i]*h[k+1]) ,斜率维护。

代码:

 

#include<cstdio>
#include<algorithm>

using namespace std;

typedef long long ll;

const int N = 50005;

int n,m, l,r;
pair<int,int> a[N],s[N];
pair<int,ll> q[N];
int x,y;
ll dp[2][N];

inline void push(int k,ll b){
    while(l<r && (q[r].second-q[r-1].second)*(k - q[r].first)<=(b-q[r].second)*(q[r].first-q[r - 1].first)) r--;
    q[++r]=make_pair(k,b);
}

inline void pop(ll x){
    while(l<r && (q[l].first - q[l+1].first)*x >= q[l+1].second - q[l].second) l++;
}

template <class T>
inline bool rd(T &ret) {
    char c; int sgn;
    if(c = getchar() , c == EOF) return false;
    while(c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return true;
}

int main(){
    while(~scanf("%d%d",&n,&m)){
        for(int i=0;i<n;i++)rd(a[i].first),rd(a[i].second);
        sort(a,a+n);
        int cnt=1,mxb=a[n-1].second;
        s[0]=a[n-1];
        for(int i=n-2;i>=0;i--)if(a[i].second>mxb){
            mxb = a[i].second;
            s[cnt++]=a[i];
        }
        n=cnt;
        ll mxa=s[0].first;
        for(int i=0;i<n;i++) dp[0][i]=mxa*s[i].second;
        ll ans=dp[0][n-1];
        x=0;
        y=1;
        if(m>n) m=n;
        for(int k=1;k<m;k++){
            l=0;r=-1;
            push(s[k].first,dp[x][k-1]);
            for(int i=k;i<n;i++){
                pop(s[i].second);
                dp[y][i]=q[l].second+(ll)q[l].first*s[i].second;
                push(s[i+1].first,dp[x][i]);
            }
            x^=1;
            y^=1;
            if(dp[x][n-1]<ans) ans=dp[x][n-1];
            else break;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2015-08-02 12:35  mithrilhan  阅读(179)  评论(0编辑  收藏  举报