bzoj1597: [Usaco2008 Mar]土地购买

题目链接

bzoj1597: [Usaco2008 Mar]土地购买

题解

按照x,y降序排序
发现当$ x_i \leq x_j$ 且$ y_i \leq y_j$时,分在同一组的话是可以合并的...
合并之后的序列x不降,y单减
然后dp方程就好写了吧
然后斜率优化一下就可以了吧 QUQ

代码

#include<cstdio>
#include<cstring> 
#include<algorithm> 
inline int read() { 
    int x = 0,f = 1; 
    char c = getchar(); 
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();} 
    while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar(); 
    return x * f; 
}
#define int long long 
const int maxn = 50007;
struct Block {
    int x,y; 
    bool operator < (const Block &a)const { 
        if(x == a.x) return y < a.y; 
        else return x < a.x;  
    } 
}block[maxn]; 
int x[maxn],y[maxn],q[maxn]; 
int n,dp[maxn]; 
double slop(int k,int j) {
    return double (dp[j] - dp[k] ) / double (y[k + 1] - y[j + 1]);
}
//dp[i] = min{ dp[j] + a[i] * b[j + 1] } 
main() {
    n = read();
    for(int i = 1;i <= n;++ i) { 
        block[i].x = read(); 
        block[i].y = read(); 
    } 
    std::sort(block + 1,block + n + 1); 
    int tot = 0; 
    for(int i = 1;i <= n;++ i) {
        while(tot && block[i].y >= y[tot]) tot --; 
        x[++ tot] = block[i].x;y[tot] = block[i].y;             
    }
    int l = 0,r = 0; 
    for(int i = 1;i <= n;++ i) {
        while(l < r && slop(q[l],q[l + 1]) < x[i] ) l ++;
        int t = q[l];
        dp[i] = dp[t] + y[t + 1] * x[i]; 
        while(l < r && slop(q[r],i) < slop(q[r - 1],q[r]) ) r--;
        q[++ r] = i; 
    }
    printf("%lld\n",dp[tot]) ;
    return 0;
}

posted @ 2018-05-02 19:51  zzzzx  阅读(118)  评论(0编辑  收藏  举报