Description
n个蛋糕,第i个蛋糕是一个底面半径为r高度为h的圆柱体,现在要用这些蛋糕摞成一个大蛋糕,要求是大编号的蛋糕摞在小编号的蛋糕上面,大体积的蛋糕摞在小体积的蛋糕上面,问最后摞起来的蛋糕总体积最大值
Input
第一行一整数n表示蛋糕数量,之后n行每行输入两整数r和h表示该蛋糕的底面半径和高度(1<=n<=1e5,1<=r,h<=1e4)
Output
输出一个实数表示摞起来的蛋糕总体积最大值
Sample Input
2
100 30
40 10
Sample Output
942477.796077000
Solution
以dp[i]表示以第i个蛋糕为最上面一个蛋糕时蛋糕总体积最大值,那么有dp[i]=max(dp[j])+a[i],其中a[i]是第i个蛋糕的体积,1<=j < i且a[j] < a[i],直接转移是O(n^2)的,拿线段树优化一下,把所有蛋糕按体积升序排后离散化一下,dp[i]插入到线段树中的位置为第i个蛋糕的体积在离散化数组中的位置,这保证了体积大的蛋糕是通过体积小的蛋糕转移过来,按编号从小到大求第i个蛋糕的dp值,这保证了大编号的蛋糕由小编号的蛋糕转移过来,对于第i个蛋糕,在离散化数组中二分搜索找到pos满足a[pos] < a[i]且a[pos+1]>=a[i],在线段树中找到区间[1,pos]中的最大值,加上a[i]即为dp[i]的值,将其插入到线段树中第pos+1个位置,最后线段树中最大值即为答案
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 111111
#define ls (t<<1)
#define rs ((t<<1)|1)
ll Max[maxn<<3];
ll h[maxn],a[maxn];
int n;
void push_up(int t)
{
Max[t]=max(Max[t],max(Max[ls],Max[rs]));
}
void update(int L,int R,int l,int r,int t,ll v)
{
if(L<=l&&r<=R)Max[t]=max(Max[t],v);
else
{
int mid=(l+r)>>1;
if(L<=mid)update(L,R,l,mid,ls,v);
if(R>mid)update(L,R,mid+1,r,rs,v);
}
push_up(t);
}
ll query(int L,int R,int l,int r,int t)
{
if(R<L)return 0;
if(L<=l&&r<=R)return Max[t];
ll ans=0;
int mid=(l+r)>>1;
if(L<=mid)ans=max(ans,query(L,R,l,mid,ls));
if(R>mid)ans=max(ans,query(L,R,mid+1,r,rs));
return ans;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
int hh,rr;
scanf("%d%d",&rr,&hh);
a[i]=h[i]=1ll*rr*rr*hh;
}
sort(h+1,h+n+1);
memset(Max,0,sizeof(Max));
for(int i=1;i<=n;i++)
{
int pos=lower_bound(h,h+n,a[i])-h-1;
update(pos+1,pos+1,1,n,1,query(1,pos,1,n,1)+a[i]);
}
double ans=acos(-1.0)*Max[1];
printf("%.15f\n",ans);
}
return 0;
}