标签: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