标签:des style class blog code java
2 1 1 100 100 1 2 2 1 100 100 1
10000 200
/*分析:
对所有人进行h从大到小排序,然后扫描数组的时候只扫描w递增的
如果当前w比前面的w小则该点根本不需要,因为可以随便加入到前面已经开辟的洞中
假定:
dp[i][j]表示前i个人打j个洞耗费的最少面积
则dp[i][j]=Min(dp[k][j-1]+w[i]*h[k+1])
=>dp[i][j]=dp[k][j-1]+w[i]*h[k+1]
这里有w[i]*h[k+1]所以不能直接用单调队列维护最小值
假定k2<k前i个数在k点分割取得最优值,h[k2+1]>=h[k+1]
则满足:
dp[k][j-1]+w[i]*h[k+1]<=dp[k2][j-1]+w[i]*h[k2+1]
=>(dp[k][j-1]-dp[k2][j-1])/(-h[k+1]-(-h[k2+1]))<=w[i]
假定:
y1=dp[k][j-1]
x1=-h[k+1];
y2=dp[k2][j-1]
x2=-h[k2+1];
所以变成(y1-y2)/(x1-x2)<=sum[i]
斜率DP,维护斜率递增(下凸斜率折线)即可
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <map>
#include <iomanip>
#define INF 1ll<<60
typedef long long LL;
using namespace std;
const int MAX=50000+10;
int n,k,index,head,tail,Id;
LL dp[MAX][2],q[MAX];//dp采用滚动数组形式
struct Node{
LL w,h;
bool operator<(const Node &a)const{
return h>a.h;
}
}s[MAX];
LL GetY(int k,int k2){
return dp[k][index^1]-dp[k2][index^1];
}
LL GetX(int k,int k2){
return s[k2+1].h-s[k+1].h;
}
void DP(){
index=0;
memset(dp,0,sizeof dp);
for(int i=1;i<=n;++i)dp[i][index]=INF;
for(int j=1;j<=k;++j){
index=index^1;
head=tail=0;
q[tail++]=0;
Id=0;
for(int i=1;i<=n;++i){
if(s[i].w <= s[Id].w)continue;
Id=i;
while(head+1<tail && GetY(q[head+1],q[head])<=GetX(q[head+1],q[head])*s[i].w)++head;
dp[i][index]=dp[q[head]][index^1]+s[i].w*s[q[head]+1].h;
while(head+1<tail && GetY(i,q[tail-1])*GetX(q[tail-1],q[tail-2])<=GetY(q[tail-1],q[tail-2])*GetX(i,q[tail-1]))--tail;
q[tail++]=i;
}
}
}
int main(){
while(~scanf("%d%d",&n,&k)){
for(int i=1;i<=n;++i)scanf("%I64d%I64d",&s[i].w,&s[i].h);
sort(s+1,s+n+1);
DP();
printf("%I64d\n",dp[Id][index]);
}
return 0;
}
/*
3 1
2 6
4 4
2 2
*/
标签:des style class blog code java
原文地址:http://blog.csdn.net/xingyeyongheng/article/details/30250881