HDU6047 Maximum Sequence

题目连接

题意

​ 给定长度为n的数列A和数列B,利用已经存在的两数列A,B生成A数列的后续 an+1,an+2,......,a2n 项,要求生成的新的项时满足条件 aimax{ajjbkj<i} ,式中k为所选用的数,每个 bk 限定只能选一次。求取 max{2nn+1ai}

分析

​ 要求取最大值,显然 ai=max{ajjbkj<i} ,问题转换成了如何分配k使得最后和最大。假定 appaqq 对于所有的 p<q 成立, attaqq 对于所有的 t>q 成立。那么对于所有的 bkq 显然生成的数均为 aqq ,考虑到所有生成的数 ai 对后续的影响为 aii ,想要使得后续的数尽可能的大,由于 ai 固定不变,则在 i 最小时aii最大。所以可以贪心的采用每次生成的数均为可行方案中最大的结果,最后求取 2nn+1ai 的结果必然也是最大值。比赛期间使用的优先队列来快速寻找到最大的数,然后用树状数组记录 bk 的值,快速能够生成的 ai 的具体数列。赛后发现其实想多了,不需要使用树状数组,一个前缀和就可以获取具体数量了。具体可以看看比赛时的代码

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
#define LL long long
#define MAXN 250250
const int mod=1e9+7;
struct Node{
    int v,idx;
    Node(int _v,int _idx):v(_v),idx(_idx){}
    Node(){}
    friend bool operator<(Node n1,Node n2){
        if(n1.v!=n2.v)
            return n1.v<n2.v;
        return n1.idx<n2.idx;
    }
};
int bin[MAXN];
int a[MAXN];
int b[MAXN];
int lowbit(int x){
    return x&-x;
}
int sum(int x){
    int ret=0;
    while(x){
        ret+=bin[x];
        x-=lowbit(x);
    }
    return ret;
}
int add(int x){
    while(x<MAXN){
        bin[x]++;
        x+=lowbit(x);
    }
}

int query(int x,int y){
    return sum(y)-sum(x-1);
}
int main(){
    int n;
    while(~scanf("%d",&n)){
        priority_queue<Node> q;
        memset(bin,0,sizeof(bin));
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
            q.push(Node(a[i]-i,i));
        }
        for(int i=1;i<=n;++i){
            scanf("%d",&b[i]);
            add(b[i]);
        }
        LL ans=0;
        int res=n,mx=0,pos=n+1;
        while(res && !q.empty()){
            Node tmp=q.top();
            q.pop();
            if(tmp.idx<=mx)
                continue;
            if(tmp.idx>mx){
                if(tmp.idx>n){
                    ans+=tmp.v*1ll*res;
                    res=0;
                    continue;
                }
                else{
                    int num=query(mx+1,tmp.idx);
                    ans+=tmp.v*1ll*num;
                    q.push(Node(tmp.v-pos,pos));
                    pos+=num;
                    res-=num;
                    mx=tmp.idx;
                    continue;
                }
            }
        }
        ans%=mod;
        printf("%I64d\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值