Manthan, Codefest 17 B. Marvolo Gaunt‘s Ring(线段树+思维)

50 篇文章 0 订阅

 

有 n 个数,以及 p,q,r

要求找到三个数 \small i,j,k 使得 \small pa[i]+qa[j]+ra[k] 最大,其中 \small i<=j<=k  

由于题目具有后效性,开始没有注意到,枚举 i∈[1,n] 使得 a[i]*p,然后用线段树找到 j∈[i,n] 使得 a[j]*q,再找到 k∈[j,n] 使得 a[k]*r,但是这样的做法是不对的,只能过到 12 个样例

因为每一步都是最优的,并不能代表整体最优

如果枚举 j,在从区间 [1,j] 和 [j,n] 分别找 i 和 k 的话这样是正确的,其余上述的做法不同的是,上述做法没有考虑后效性而缩小了区间范围,而这样枚举所有情况全部考虑到了

const int N=1e5+5;

    int n,m;
    int i,j,k;
    int a[N];
    struct Node
    {
        int l,r;
        pll maxx,minn;
        #define lson id<<1
        #define rson id<<1|1
    }t[N<<2];

void push_up(int id)
{
    t[id].maxx=max(t[lson].maxx,t[rson].maxx);
    t[id].minn=min(t[lson].minn,t[rson].minn);
}

void build(int l,int r,int id)
{
    t[id].l=l,t[id].r=r;
    if(l==r){ t[id].maxx={a[l],l},t[id].minn={a[l],l}; return ; }
    else {
        int mid=l+r>>1;
        build(l,mid,lson);
        build(mid+1,r,rson);
        push_up(id);
    }
}

pll query(int l,int r,int id,ll tag)
{
    int L=t[id].l,R=t[id].r;
    if(L>=l && r>=R) return tag>0?t[id].maxx:t[id].minn;
    else{
        int mid=L+R>>1;
        if(tag>0){
            pll ans={-9e18,l};
            if(mid>=l) ans=max(ans,query(l,r,lson,tag));
            if(r>=mid+1) ans=max(ans,query(l,r,rson,tag));
            return ans;
        } else{
            pll ans={9e18,l};
            if(mid>=l) ans=min(ans,query(l,r,lson,tag));
            if(r>=mid+1) ans=min(ans,query(l,r,rson,tag));
            return ans;
        }
    }
}

int main()
{
    ll p,q,r;
    while(~sd(n)){
        sll(p),sll(q),sll(r);
        forn(i,1,n) sd(a[i]);
        build(1,n,1);
        //forn(i,1,n) dbg(query(i,n,1,1).first);
        ll ans,maxx=-9e18;
        for(int i=1;i<=n;i++){
            ans=q*a[i];
            if(p){
                pll tmp=query(1,i,1,p);
                ans+=p*tmp.first;
            }
            if(r){
                pll tmp=query(i,n,1,r);
                ans+=r*tmp.first;
            }
            maxx=max(maxx,ans);
        }
        pll(maxx);
    }
    //PAUSE;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值