Codeforces Round #343 (Div. 2) D. Babaei and Birthday Cake(线段树+离散化优化DP)

来源:互联网 发布:mac系统外置光驱 编辑:程序博客网 时间:2024/05/17 06:28

题目链接:点击打开链接

题意:给出n个圆柱体的地面半径和高, 要求只能有一个直接放在桌子上, 其他的要放在他上面, 第i个能放在第j个上面的条件是:当且仅当第i个的体积大于第j个且j < i 。 求能叠起来的最大体积。

思路:一看就是一个DP, 而且状态很容易表示, d[i]表示到第i个为止能得到的最大总体积。   转移到 max(d[j]) + a[i], (j < i && a[i] > a[j])。  但是n非常大, 显然要优化, 因为第二层循环所做的事情就是在i之前找一个满足a[j] > a[i]的最大dp[j]。  那么为了同时满足两个条件, 可以把其中一个条件(每个的体积)当成线段树下标, 变相维护了一个条件, 又因为小标必须是整数, 且体积太大, 我们想到了离散化。  那么这题就很简单了, 离散化每个的体积, 用体积作为线段树下标, 维护一个区间最大值, 这个值就是之前已经加进去的dp[j]。 

细节参见代码:

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<string>#include<vector>#include<stack>#include<bitset>#include<cstdlib>#include<cmath>#include<set>#include<list>#include<deque>#include<map>#include<queue>#define Max(a,b) ((a)>(b)?(a):(b))#define Min(a,b) ((a)<(b)?(a):(b))using namespace std;typedef long long ll;typedef long double ld;const ld eps = 1e-9, PI = 3.1415926535897932384626433832795;const int mod = 1000000000 + 7;const int INF = int(1e9);const ll INF64 = ll(1e18);const int maxn = 100000 + 10;int T,n,m;ll d[maxn],b[maxn];ll maxv[maxn<<2];struct node {    ll r, h, v;}a[maxn];void PushUp(int o) {    maxv[o] = max(maxv[o<<1], maxv[o<<1|1]);}void build(int l, int r, int o) {    int m = (l + r) >> 1;    maxv[o] = 0;    if(l == r) return ;    build(l, m, o<<1);    build(m+1, r, o<<1|1);}void update(int L, int R, int v, int l, int r, int o) {    int m = (l + r) >> 1;    if(L <= l && r <= R) {        if(maxv[o] < d[v]) {            maxv[o] = d[v];        }        return ;    }    if(L <= m) update(L, R, v, l, m, o<<1);    if(m < R) update(L, R, v, m+1, r, o<<1|1);    PushUp(o);}ll query(int L, int R, int l, int r, int o) {    int m = (l + r) >> 1;    if(L <= l && r <= R) {        return maxv[o];    }    ll ans = 0;    if(L <= m) ans = max(ans, query(L, R, l, m, o<<1));    if(m < R) ans = max(ans, query(L, R, m+1, r, o<<1|1));    PushUp(o);    return ans;}int main() {    scanf("%d",&n);    for(int i=1;i<=n;i++) {        scanf("%I64d%I64d",&a[i].r,&a[i].h);        a[i].v = a[i].r * a[i].r * a[i].h;        b[i] = a[i].v;    }    sort(b+1, b+1+n);    int m = unique(b+1, b+1+n) - b - 1;    build(1, m, 1);    ll cur = 0;    for(int i=1;i<=n;i++) {        int L = lower_bound(b+1, b+1+m, a[i].v) - b;        ll v;        if(L > 1) v = query(1, L-1, 1, m, 1);        else v = 0;        d[i] = (v + a[i].v);        update(L, L, i, 1, m, 1);        cur = max(cur, d[i]);    }    double ans = PI * cur;    printf("%.8f\n",ans);    return 0;}



0 0