629D

题意:给定n个圆柱体的半径和高,输入顺序即圆柱体的编号顺序。现在规定,只有编号和体积均大于另一个圆柱体,才能放到另一个圆柱体的体积上面。求能叠加的最大体积是多少。

酝酿了我三天,才理解。自己敲个代码,还超时了,但是把思路记录一下吧,实在不知道哪里超时了。

思路:dp+线段树维护。本质是求递增序列的最大和。设dp[i]表示以编号为i的圆柱体为顶部的圆柱。大问题拆分成子问题:dp[i]=max(dp[j])  +  v[i] ,j表示可以放在i号圆柱体下的合法圆柱体,即体积和编号均小于 i 。但是如果直接枚举状态,然后 去暴力搜索合法的 dp[j],会超时,因此,第二层for循环,合法的dp[j]用线段树维护(但是我还是超时了uhnnnnnnn,,无语啊)。先确定要维护的区间,维护区间为v即每个圆柱体的体积,再把体积从小到大排序。再去遍历状态参量  i  ,每一次找到 v[i]在体积区间当中所处的位置。然后在体积区间里小于v[i]的部分里找最大的dp[j]。其实一开始我有个地方不理解,就是只维护体积区间,每次去查1至 i-1 区间里的最大的dp[j],但是我觉得编号不一定满足 j<i,事实证明想多了,因为每一次更新v[i]所处位置的dp[i]值时,,是按照编号顺序来更新的,也就是说哪些体积比它小,但是编号比他大的在后面才会更新,当前这步是不会更新的。

本题,线段树的精髓,每当求出一个位置的dp[i]的时候,都去包含此位置的区间,并且由于还是按照输入顺序来更新的,所以不存在体积小,但是序号大的情况。

上个超时代码吧。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;


struct Node
{
    int l,r;
    int dat;
}t[100000*4];

long long dp[100000*4];
long long v[100000*4];
int H[100000*4];
long long ans=0;
const double PI=acos(-1.0);
int n;

void build(int p,int l,int r)
{
    t[p].l=l,t[p].r=r;
    //int mid=(l+r)>>1;
    if(l==r){ t[p].dat=0;return;}
    int mid=(l+r)>>1;
    build(p*2,1,mid);
    build(p*2+1,mid+1,r);
    t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}

ll query(int p,int l,int r)
{
    if(l>r) return 0;
    if(l<=t[p].l&&t[p].r<=r) return t[p].dat;
    int mid=(t[p].l+t[p].r)>>1;
    ll val=-1<<30;
    if(mid>=l) val=max(val,query(p*2,l,r));
    if(mid<r) val=max(val,query(p*2+1,l,r));
    return val;    
}

void update(int p,int x,int v)
{
    if(t[p].l==t[p].r){t[p].dat=v;return;}
    int mid=(t[p].l+t[p].r)>>1;
    if(x<=mid) update(p*2,x,v);
    else update(p*2+1,x,v);
    t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}


int main()
{
    cin>>n;
    int r,h;
    for(int i=1;i<=n;i++)
    {
    cin>>r>>h;
    v[i]=r*r*h;
    H[i]=v[i];
    dp[i]=v[i];
    }
    
    sort(H+1,H+1+n);
    build(1,1,n);
    for(int i=1;i<=n;i++)
    {
        int cur=lower_bound(H+1,H+1+n,v[i])-H;
        dp[i]=max(dp[i],query(1,1,cur-1)+v[i]);
        update(1,cur,dp[i]);
        ans=max(ans,dp[i]);
    }
    
    printf("%.15lf",PI*ans);
 return 0;    
} 
原文地址:https://www.cnblogs.com/rainyskywx/p/10719472.html