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

题目链接:点击打开链接

题意:给出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;
}
时间: 2024-11-08 08:47:58

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

Codeforces Round #250 (Div. 1) D. The Child and Sequence (线段树)

题目链接:http://codeforces.com/problemset/problem/438/D 给你n个数,m个操作,1操作是查询l到r之间的和,2操作是将l到r之间大于等于x的数xor于x,3操作是将下标为k的数变为x. 注意成段更新的时候,遇到一个区间的最大值还小于x的话就停止更新. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5

Codeforces Round #250 (Div. 1) D. The Child and Sequence 线段树 区间求和+点修改+区间取模

D. The Child and Sequence At the children's day, the child came to Picks's house, and messed his house up. Picks was angry at him. A lot of important things were lost, in particular the favorite sequence of Picks. Fortunately, Picks remembers how to

Codeforces Round #350 (Div. 2) E. Correct Bracket Sequence Editor 线段树模拟

E. Correct Bracket Sequence Editor Recently Polycarp started to develop a text editor that works only with correct bracket sequences (abbreviated as CBS). Note that a bracket sequence is correct if it is possible to get a correct mathematical express

Codeforces Round 261 Div.2 D Pashmak and Parmida&#39;s problem --树状数组

题意:给出数组A,定义f(l,r,x)为A[]的下标l到r之间,等于x的元素数.i和j符合f(1,i,a[i])>f(j,n,a[j]),求有多少对这样的(i,j). 解法:分别从左到右,由右到左预处理到某个下标为止有多少个数等于该下标,用map维护. 然后树状数组更新每个f(j,n,a[j]),预处理完毕,接下来,从左往右扫过去,每次从树状数组中删去a[i],因为i != j,i不能用作后面的统计,然后统计getsum(inc[a[i]]-1), (inc表示从左到右),即查询比此时的a[i]

Codeforces Round #424 (Div. 2) D 思维 E set应用,树状数组

Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) D. Office Keys 题意:一条直线上,有个办公室坐标 p,有 n个人在a[i],有 k把钥匙在b[i],每个人必须拿到一把钥匙,然后到办公室.问怎么安排花的时间最短. tags:还是不懂套路啊..其实多画两下图就能够感觉出来,2333 关键是要看出来,n个人拿的 n把钥匙应该是连续的. 然后,就是瞎暴力.. #include<bits/stdc++.h> usi

Codeforces Round #343 (Div. 2) (C. Famil Door and Brackets(DP))

题目链接:点击打开链接 题意:给你一个长度为m的只含()的括号串s, 要求在s两端在加两个串p和q, 使得总长度为n,并且平衡, 平衡是指任意前缀串的(都不少于), 并且整个串的(和)一样多. 思路:我们不难想到这样一个DP, d[i][j]表示长度为i的串,(比)多j个(或者)比(多j个, 是等价的)的方案数.  那么转移很简单: if(j > 0) d[i][j] += d[i-1][j-1] ;    d[i][j] += d[i-1][j+1]. 然后为了满足那两个条件, 我们计算出s串

Codeforces Round #343 (Div. 2) B. Far Relative’s Problem

题意:n个人,在规定时间范围内,找到最多有多少对男女能一起出面. 思路:ans=max(2*min(一天中有多少个人能出面)) 1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstdio> 6 #include<set> 7 #include<map> 8 #include<ve

Codeforces Round #343 (Div. 2) A. Far Relative’s Birthday Cake

水题 1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstdio> 6 #include<set> 7 #include<map> 8 #include<vector> 9 #include<cstring> 10 #include<stack> 1

Codeforces Round #365 (Div. 2) D. Mishka and Interesting sum (离线树状数组+前缀xor)

题目链接:http://codeforces.com/contest/703/problem/D 给你n个数,m次查询,每次查询问你l到r之间出现偶数次的数字xor和是多少. 我们可以先预处理前缀和Xor[i],表示1~i的xor和.因为num^num=0,所以Xor[r] ^ Xor[l - 1]求的是l~r之间出现奇数次的数字xor和. 那怎么求偶数次的呢,那我们可以先求l到r之间不重复出现数字的xor(比如1 1 2 求的是1 ^ 2),然后再xor以上求出的Xor[r] ^ Xor[l