Time Limit: 1000MS | Memory Limit: 65536K | |||
Total Submissions: 77 | Accepted: 10 |
Description
随着YYHS的OI集训队人数急剧增加,原有的小机房已经容纳不了数量庞大的队员。
于是史老师决定租用一些实验室机位供队员们训练,他正在考虑为N (1 <= N <= 50,000)位队员租用机位。实验室管理员根据要求给出了N个机位的长和宽,每个机位的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000).
而机位的租用价格是它的面积,实验室管理员也提出,可以同时租用多个机位. 租用这一组机位的价格是它们最大的长乘以它们最大的宽, 但是机位的长宽不能交换. 如果想租下一个3x5的机位和一个5x3的机位,则他需要付5x5=25.
于是问题出现了,史老师希望租下所有的机位,但是他发现分组来租这些机位可以节省经费. 他需要你帮助他找到最小的经费.
Input
* 第1行: 一个数: N
* 第2..N+1行: 每行包含两个数,分别为机位的长和宽
Output
* 第一行: 最小的可行费用.
Sample Input
4
100 1
15 15
20 5
1 100
Sample Output
500
这题如果是用n*n的dp,会超时,所以要用斜率优化,和hdu3669差不多的思路。
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 999999999999999999
#define maxn 50050
struct node{
ll w,h;
}a[maxn],b[maxn];
bool cmp(node a,node b){
if(a.w==b.w)return a.h>b.h;
return a.w>b.w;
}
ll dp[maxn];
ll q[1111111];
ll getup(int x)
{
return dp[x];
}
ll getdown(int x)
{
return -b[x+1].w;
}
int main()
{
int n,m,i,j,tot,k;
while(scanf("%d",&n)!=EOF)
{
for(i=1;i<=n;i++){
scanf("%d%d",&a[i].w,&a[i].h);
}
sort(a+1,a+1+n,cmp);
tot=1;b[tot].w=a[1].w;b[tot].h=a[1].h;
for(i=2;i<=n;i++){
if(b[tot].h>=a[i].h)continue;
tot++;b[tot].w=a[i].w;b[tot].h=a[i].h;
}
int front,rear;
front=1;rear=1;
q[rear]=0;
for(i=1;i<=tot;i++){
//dp[i]=b[1].w*b[i].h; 这里如果前面不把0加入队列的话,那么这句话要加上。
while(front<rear && getup(q[front+1])-getup(q[front])<=b[i].h*(getdown(q[front+1])-getdown(q[front]) ) ){
front++;
}
k=q[front];
dp[i]=dp[k]+b[k+1].w*b[i].h;
//dp[i]=min(dp[i],dp[k]+b[k+1].w*b[i].h);
while(front<rear && ( getup(q[rear])-getup(q[rear-1] ) )*(getdown(i)-getdown(q[rear] ))>=( getup(i)-getup(q[rear] ) )*(getdown(q[rear])-getdown(q[rear-1] )) ){
rear--;
}
rear++;
q[rear]=i;
}
printf("%lld
",dp[tot]);
}
return 0;
}