【斜率优化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;
}
= =这道题折腾了我一下午 让我没能愉快地去写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;
}
相关文章推荐
- 动态规划DP的斜率优化 个人浅解 附HDU 3669 Cross the Wall
- HDU 3669 Cross the Wall (斜率优化DP)
- hdu 3669 Cross the Wall(斜率优化DP)
- Cross the Wall UVALive - 5097 (贪心+斜率dp)
- Cross the Wall UVALive - 5097 (贪心+斜率dp)
- UVALive - 5097 Cross the Wall(斜率优化)
- Cross the Wall UVALive - 5097 (贪心+斜率dp)
- Cross the Wall UVALive - 5097 (贪心+斜率dp)
- Cross the Wall UVALive - 5097 (贪心+斜率dp)
- Cross the Wall UVALive - 5097 (贪心+斜率dp)
- Cross the Wall UVALive - 5097 (贪心+斜率dp)
- Cross the Wall UVALive - 5097 (贪心+斜率dp)
- Cross the Wall UVALive - 5097 (贪心+斜率dp)
- CSU 1963 Feed the rabbit(斜率优化dp)
- hdu3669 Cross the Wall
- CodeForces 311B/CSU 1963 Cats Transport/Feed The Rabbit(斜率优化dp)
- DP——斜率优化专题(pku3709,hdu3669)
- CF 319C - Kalila and Dimna in the Logging Industry 斜率优化DP
- CSU-1963 Feed the rabbit(斜率优化dp)
- 文章标题 CSU 1963: Feed the rabbit (斜率DP优化)