Codeforces Round #343 (Div. 2) D. Babaei and Birthday Cake

D. Babaei and Birthday Cake
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

As you know, every birthday party has a cake! This time, Babaei is going to prepare the very special birthday party's cake.

Simple cake is a cylinder of some radius and height. The volume of the simple cake is equal to the volume of corresponding cylinder. Babaei has n simple cakes and he is going to make a special cake placing some cylinders on each other.

However, there are some additional culinary restrictions. The cakes are numbered in such a way that the cake number i can be placed only on the table or on some cake number j where j < i. Moreover, in order to impress friends Babaei will put the cake i on top of the cake j only if the volume of the cake i is strictly greater than the volume of the cake j.

Babaei wants to prepare a birthday cake that has a maximum possible total volume. Help him find this value.

Input

The first line of the input contains a single integer n (1 ≤ n ≤ 100 000) — the number of simple cakes Babaei has.

Each of the following n lines contains two integers ri and hi (1 ≤ ri, hi ≤ 10 000), giving the radius and height of the i-th cake.

Output

Print the maximum volume of the cake that Babaei can make. Your answer will be considered correct if its absolute or relative error does not exceed 10 - 6.

Namely: let's assume that your answer is a, and the answer of the jury is b. The checker program will consider your answer correct, if .

Examples
input
2
100 30
40 10
output
942477.796077000
input
4
1 1
9 7
1 4
10 7
output
3983.539484752
Note

In first sample, the optimal way is to choose the cake number 1.

In second sample, the way to get the maximum volume is to use cakes with indices 12 and 4.



注意update函數賦值的那個形參val必須爲long long,防止出現溢出錯誤。

對於任意位置i,求出1~i-1的區間內比a[i]小的數中的最大值,想到用線段樹維護。

建立線段樹有兩種方法:

1種是按照原數組建立從1~n的線段樹,遍歷新數組。這時結構體排序要注意數值相等的相鄰的數字,原有下標按照降序排列。

原因是這樣在遍歷排序後的數組時,線段樹中[1,i)區間中不會因爲有和自己數值相等,但下標小的元素影響區間最大值。

如果按照升序排序會WA

2.按照新數組建立從1~n的線段樹,遍歷原有數組。線段樹查詢區間的爲1到比lower_bound(...)-1的位置。遍歷原數組的好處是隻用查找當前線段數中比a[i]小的所有元素的區間。不會有相同數值的元素影響結果的情況。


用map或者set也可以解。

用map的時候,建立<a[i],dp[a[i]>的map。用map的lower_bound函數找到比mp下標小的index中,dp值最大的item。

注意map會自動按照key的從小到大順序排列。在處理的時候需要從lower_bound到end位置依次遍歷,除去後面key>=a[i]的,且dp值小於等於當前位置dp值的item。這樣纔可以始終保證map通過lower_bound查找出來的那個lower_bound-1位置的dp值是前面最大的。

例子:5 1 6 2 5 7,5 2 3 2 3,5 1 6 2 3 4 5 7。第一個例子是要注意,當5處在a[1]位置時,後面再次出現5時,dp值會大於5。所以刪除時與該元素key相同的元素,可能value更小。第二個例子中3的dp值始終爲5,兩個3的dp值是相等的。第一個例子中第2個5出現時,需要刪除6 7這個元素,這樣才保證局部最大。即保證了map中key升序的同時,value也升序。單調性。


#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#define CLR(x) memset(x,0,sizeof(x))
#define ll long long
using namespace std;

int n;
ll tree[100010<<2],a[100010],b[100010],dp[100010];

void PushUp(int rt){
  tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}

void build(int l,int r,int rt){
   if(l==r){tree[rt]=0;return;}
   int m=(l+r)>>1;
   build(l,m,rt<<1);
   build(m+1,r,rt<<1|1);
   PushUp(rt);
}

void update(int p,ll val,int l,int r,int rt){
   if(l==r){tree[rt]=val;return;}
   int m=(l+r)>>1;
   if(p<=m) update(p,val,l,m,rt<<1);
   else update(p,val,m+1,r,rt<<1|1);
   PushUp(rt);
}

ll query(int L,int R,int l,int r,int rt){
   if(L<=l&&r<=R) return tree[rt];
   int m=(l+r)>>1;
   ll ans=0;
   if(L<=m) ans=max(ans,query(L,R,l,m,rt<<1));
   if(R>m) ans=max(ans,query(L,R,m+1,r,rt<<1|1));
   return ans;
}

int main(){
   while(~scanf("%d",&n)){
     for(int i=1;i<=n;i++){
        int r,h;
        scanf("%d%d",&r,&h);
        a[i]=b[i]=(ll)r*r*h;
     }
     sort(a+1,a+n+1);
     build(1,n,1);
     for(int i=1;i<=n;i++){
        int pos=lower_bound(a+1,a+n+1,b[i])-a;
        if(pos==1) dp[i]=b[i];
        else dp[i]=query(1,pos-1,1,n,1)+b[i];
        update(pos,dp[i],1,n,1);
     }
     printf("%.12f\n",M_PI*tree[1]);
   }
}



#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#define CLR(x) memset(x,0,sizeof(x))
#define ll long long
using namespace std;

struct node
{
    ll v;
    int id;
}a[100010];
int n;
ll tree[100010<<2],dp[100010];

bool cmp(node a,node b){
    if(a.v==b.v)
        return a.id>b.id;
    return a.v<b.v;
}

void PushUp(int rt){
  tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}

void build(int l,int r,int rt){
   if(l==r){
     tree[rt]=0;
     return;
   }
   int m=(l+r)>>1;
   build(l,m,rt<<1);
   build(m+1,r,rt<<1|1);
   PushUp(rt);
}

void update(int p,ll val,int l,int r,int rt){
   if(l==r){
     tree[rt]=val;
     return;
   }
   int m=(l+r)>>1;
   if(p<=m){
     update(p,val,l,m,rt<<1);
   }else{
     update(p,val,m+1,r,rt<<1|1);
   }
   PushUp(rt);
}

ll query(int L,int R,int l,int r,int rt){
   if(L<=l&&r<=R){
     return tree[rt];
   }
   int m=(l+r)>>1;
   ll ans=0;
   if(L<=m){
     ans=max(ans,query(L,R,l,m,rt<<1));
   }
   if(R>m){
     ans=max(ans,query(L,R,m+1,r,rt<<1|1));
   }
   return ans;
}

int main(){
   while(~scanf("%d",&n)){
     for(int i=1;i<=n;i++){
        int r,h;
        scanf("%d%d",&r,&h);
        a[i].v=(ll)r*r*h;
        a[i].id=i;
     }
     sort(a+1,a+n+1,cmp);
     build(1,n,1);
     ll ans=0;
     for(int i=1;i<=n;i++){
        if(a[i].id==1){
            dp[a[i].id]=a[i].v;
        }else{
            dp[a[i].id]=query(1,a[i].id-1,1,n,1)+a[i].v;
        }
        update(a[i].id,dp[a[i].id],1,n,1);
        ans=max(ans,dp[a[i].id]);
     }
     printf("%.9f\n",M_PI*ans);
   }
}


#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;

#define ll long long
#define pi acos(-1.0)
#define maxn 100100


int main(){
	int r,h,n;
	scanf("%d",&n);
	map<ll,ll> mp;
	mp[0]=0;
	for (int i=1;i<=n;i++){
		scanf("%d%d",&r,&h);
		ll v=(ll)r*r*h;
		map<ll,ll>::iterator r=mp.lower_bound(v);
		ll sv=(--r)->second+v;
        for(r++;r!=mp.end()&&r->second<=sv;)
           mp.erase(r++);
		mp[v]=sv;
	}
	printf("%.10f\n",(--mp.end())->second * pi);
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章