codeforces #343 div2 D. Babaei and Birthday Cake(DP+離散化+線段樹優化)

題目鏈接:

http://codeforces.com/contest/629/problem/D

題目大意:

給n個圓柱體蛋糕,現在要堆一個大蛋糕,要求體積大的放在上面同時編號大的不能放在編號小的下面。問最大的體積是多少。

範圍;

n<=100000.

思路:

很容易想到:dp[i]=dp[j]+a[i](i>j&&a[i]>a[j])。

所以就有了O(n^2)的算法,但是範圍太大,會超時。

可以注意到,計算dp[i]的最大值,就是在dp[1]~dp[i-1]的範圍裏面尋找一個最大的體積。所以我們可以想到利用線段樹區間尋找最大值,爲了滿足a[i]>a[j]這個條件,我們可以先將體積進行排序,然後作爲線段樹下標。爲了表示這個下標,我們要先將體積進行離散化。然後每次尋找區間最大值,更新dp[i],將其放入線段樹。這樣答案就可以得到了。

代碼:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#define PI acos(-1.0)
#define M 100005
#define ll  __int64 
using namespace std;
int num[M];
ll vol[M],f[M];
double dp[M];
struct tree{
	int l,r;
	double ans;
}tree[M<<2];
void pushup(int i)
{
	if(tree[i].l==tree[i].r)return;
	tree[i].ans=max(tree[i<<1].ans,tree[i<<1|1].ans);
}
void build(int l,int r,int i)
{
	tree[i].l=l;
	tree[i].r=r;
	if(l==r){
		tree[i].ans=0;
		return;
	}
	int mid=l+r>>1;
	build(l,mid,i<<1);
	build(mid+1,r,i<<1|1);
	pushup(i);
}
double query(int l,int r,int i)
{
	if(tree[i].l==l&&r==tree[i].r)
	{
		return tree[i].ans;
	}
	int mid=tree[i].l+tree[i].r>>1;
	if(r<=mid)return query(l,r,i<<1);
	else if(l>mid)return query(l,r,i<<1|1);
	else return max(query(l,mid,i<<1),query(mid+1,r,i<<1|1));
	pushup(i);
}
void update(int l,int r,int i,double z)
{
	if(tree[i].l==l&&tree[i].r==r)
	{
		tree[i].ans=max(tree[i].ans,z);
		return;
	}
	int mid=tree[i].l+tree[i].r>>1;
	if(r<=mid)update(l,r,i<<1,z);
	else if(l>mid)update(l,r,i<<1|1,z);
	else {
		update(l,mid,i<<1,z);
		update(mid+1,r,i<<1|1,z);
	}
	pushup(i);
}
int main()
{
	int n,i,j,k;
	ll r[M],h[M];
	while(~(scanf("%d",&n)))
	{
		memset(num,0,sizeof(num));
		memset(dp,0,sizeof(dp));
		for(i=1;i<=n;i++)
		{
			scanf("%I64d%I64d",&r[i],&h[i]);
			vol[i]=r[i]*r[i]*h[i];
			f[i]=vol[i];
		}
		sort(vol+1,vol+1+n);
		for(i=1;i<=n;i++)
		num[i]=lower_bound(vol+1,vol+1+n,f[i])-vol;
		build(1,n,1);
		for(i=1;i<=n;i++)
		{
			if(num[i]-1==0)dp[i]=f[i];
			else dp[i]=query(1,num[i]-1,1)+f[i];
			update(num[i],num[i],1,dp[i]);
		}
		double maxi=0;
		for(i=1;i<=n;i++)
		{maxi=max(maxi,dp[i]);
	//	printf("%.2f ",dp[i]);
	}
		printf("%.8f\n",maxi*PI);
	}
}


發佈了235 篇原創文章 · 獲贊 4 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章