您的位置:首页 > 其它

【斜率优化dp】HDU3669 Cross the Wall

2015-03-19 17:51 417 查看
题目点这里

 = =这道题折腾了我一下午 让我没能愉快地去写LCT 

我最开始推出来的斜率 它居然是反的!!!还能愉快地玩耍吗???

首先把墙壁有序化 按照哪个排序都可以。。比如我们按照h升序。。

然后对于排完以后的序列 如果 i < j 并且 w[i] < w[j] 那么i是完全可以放到j里面去的

所以我们要去掉这些可以放进去的。。让他们哪凉快哪呆着去。。

然后剩下的序列就是h升序 w降序排列的了

设dp[i][j] 为前i个人开j个洞所需最小花费

显然dp[i][j] = max{ dp[k - 1][j - 1] + w[k] * h[i] } 其中k < i

令G = dp[i][j], K = h[i], x = w[k], y = dp[k-1][j-1] 则 G = y + kx 即 y = -kx + G

注意这里的k系数为负 所以计算k的时候是 (y1 - y2) / (x2 - x1)

然后经过各种艰辛的对拍 终于把它搞对了。。。注意:hdu上c++用%lld, g++用%I64d 

#include <cstdio>
#include <iostream>
#include <algorithm>

using namespace std;

int read()
{
int sign = 1, n = 0; char c = getchar();
while(c < '0' || c > '9'){ if(c == '-') sign = -1; c = getchar(); }
while(c >= '0' && c <= '9') { n = n*10 + c-'0'; c = getchar(); }
return sign*n;
}

typedef long long LL;

const int Nmax = 50005;

int N, K;
LL dp[Nmax][2], G[Nmax];

struct people{
LL w, h;
bool operator < (const people &b) const
{
if(h != b.h) return h < b.h;
return w > b.w;
}
}p[Nmax];

namespace queue{
int q[Nmax], head, tail;

inline void init(){ head = 1; tail = 0; q[head] = 0; }
inline void push_back(int x){ q[++tail] = x; }
inline void pop_back() { --tail; }
inline void pop_front() { ++head; }
inline int front() { return q[head]; }
inline int second() { return q[head + 1]; }
inline int back() { return q[tail]; }
inline int before() { return q[tail - 1]; }
inline int size() { return tail - head + 1; }
}

inline double get_k(int a, int b)
{
if(p[a].w == p[b].w) return 1e200;
return 1. * (G[a] - G[b]) / (p[b].w - p[a].w);
}

int main()
{
while(~scanf("%d%d", &N, &K))
{
for(int i = 1; i <= N; ++i)
{
scanf("%I64d%I64d", &p[i].w, &p[i].h);
dp[i][0] = 0x3f3f3f3f3f3f3fll;
}
sort(p + 1, p + N + 1);

int cnt = 1;
for(int i = 2; i <= N; ++i)
{
while(cnt > 0 && p[cnt].w <= p[i].w) --cnt;
p[++cnt] = p[i];
}
N = cnt;

using namespace queue; LL ans = 0x3f3f3f3f3f3f3fll;
for(int j = 1; j <= K && j <= cnt; ++j)
{
int nw = j & 1, pr = nw ^ 1; init();
for(int i = j; i <= N; ++i)
{
G[i] = dp[i - 1][pr];
while(size() > 1 && get_k(before(), back()) >= get_k(back(), i)) pop_back();
push_back(i);
while(size() > 1 && get_k(front(), second()) <= p[i].h) pop_front();
dp[i][nw] = G[front()] + (LL)p[front()].w * p[i].h;
}
ans = min(ans, dp
[nw]);
}
printf("%I64d\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: