codeforces 629D-Babaei and Birthday Cake(dp && 线段树或树状数组离散优化)

题目链接:【codeforces 629D】  HDU1087的升级版

有n个圆柱形的蛋糕,已知每个蛋糕的半径r和高h,将这n个蛋糕叠起来,第i个蛋糕能放在第j个蛋糕的上面(1<=j<i)的条件:第i个蛋糕的体积>第j个蛋糕的体积,问最终叠成的蛋糕的最大体积

dp[i] = max(dp[j], 1<=j<i&&a[j]<a[i]) + vol[i],这一题这样做会超时

【线段树】

用线段树记录第i个蛋糕之前满足条件的的最大dp值

将从小到大排序后的体积的序号作为线段树的下标,每访问一次vol[i],就把相应的dp[i]插入到线段树中,更新最大值

#include <bits/stdc++.h>
using namespace std;
#define ll __int64
const int inf=1e5+10;
const double pi=acos(-1.0);
ll dp[inf], vol[inf], a[inf];
struct node
{
	int l, r;
	ll maxn;
}T[inf*4];
void build(int l, int r, int u)
{
	T[u].maxn=0;
	T[u].l = l, T[u].r = r;
	if(l==r) return;
	int mid = (l+r)>>1;
	build(l, mid, u<<1);
	build(mid+1, r, u<<1|1);
}
ll query(int li, int ri, int u)
{
	if(li==T[u].l && ri==T[u].r) return T[u].maxn;
	int mid = (T[u].l+T[u].r)>>1;
	if(ri<=mid) return query(li, ri, u<<1);
	else if(li>mid) return query(li, ri, u<<1|1);
	else return max(query(li, mid, u<<1), query(mid+1, ri, u<<1|1));
}
void update(int id, int i, int u)
{
	if(T[u].l==T[u].r)
	{
		if(T[u].l==id) T[u].maxn = max(T[u].maxn, dp[i]);
		return;
	}
	int mid = (T[u].l+T[u].r)>>1;
	if(id<=mid) update(id, i, u<<1);
	if(id>mid) update(id, i, u<<1|1);
	T[u].maxn = max(T[u<<1].maxn, T[u<<1|1].maxn);
}
int main()
{
	int n;
	ll r, h;
	scanf("%d", &n);
	for(int i=1; i<=n; i++)
	{
		scanf("%I64d%I64d", &r, &h);
		a[i] = vol[i] = r*r*h;
	}	
	sort(a+1, a+1+n);
	int num = unique(a+1, a+1+n)-a-1;
	build(1, num, 1);
	ll mmaxn = -1e18;
	for(int i=1; i<=n; i++)
	{
		int id = lower_bound(a+1, a+1+num, vol[i])-a;
		if(id==1) dp[i] = vol[i];
		else dp[i] = query(1, id-1, 1) + vol[i];
		mmaxn = max(mmaxn, dp[i]);
		update(id, i, 1);
	}
//	cout<<mmaxn<<endl;
	printf("%.12lf\n", pi*mmaxn);
	return 0;
} 

【树状数组】

BIT[i]:保存的是max(dp[j], j<=i&&a[j]<a[i])

#include <bits/stdc++.h>
using namespace std;
#define ll __int64
const double pi=acos(-1.0);
const int inf=1e5+10;
ll a[inf], vol[inf], dp[inf], BIT[inf];
ll r, h;
int lowbit(int x)
{
	return x&-x;
}
ll query(int id)
{
	ll ans = 0;
	for(;id;id-=lowbit(id)) ans = max(ans, BIT[id]);
	return ans;
}
void insert(int id, ll x)
{
	for(;id<inf;id+=lowbit(id)) 
		BIT[id] = max(BIT[id], x);
}
int main()
{
	int n;
	scanf("%d", &n);
	for(int i=1;i<=n; i++)
	{
		scanf("%I64d%I64d", &r, &h);
		a[i] = vol[i] = r*r*h;
	}
	sort(a+1, a+1+n);
	int num = unique(a+1, a+1+n)-a-1;
	ll maxn = -1e18;
	for(int i=1; i<=n; i++)
	{
		int id = lower_bound(a+1, a+1+num, vol[i])-a;
		dp[i] = query(id-1) + vol[i];
		maxn = max(dp[i], maxn);
		insert(id, dp[i]); 
	}
	printf("%.12lf\n", pi*maxn);
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值