HDU6047---Maximum Sequence(2017多校联赛C题)

【题目来源】http://acm.hdu.edu.cn/showproblem.php?pid=6047
【题意】
给出序列a和序列b,均有n项,让求后n项的最大和。
并且给出了一个关系,是a[x] =max( a[j]-j),(b[k]<=j小于i)
我的理解是:因为b[k]是只能用一次的,所以,就使得a[j]-j这个式子的最大值要多次利用,怎么才能多次利用呢?就要考虑到b[k]对a[j]取值的影响。
比如样例:
8 11 8 5
3 1 4 2
这里,第一步取b数组中的2,所以a[2]…a[4]都可以用,但是当然要取最大值,所以取出11-2,也就是a[5]=9,
第二部取b数组中的1,此时,a[1]..a[5]都可以用,当然,虽然加了a[5],但是a[2]-2依旧是最大,所以使用。
也就是说,要使得最大的值尽可能多次利用,就是解决本题的关键。

//利用优先队列每次挑出最大值,根据他对应的j去处理对应的b[k]
#include<map>
#include<queue>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
typedef long long LL;
int b[250000+10];
int w[250000+10];
struct pp
{
    int index;
    int ans;
}a[250000+10];
struct cmp
{
    bool operator()(pp s,pp t)
    {
        if(s.ans==t.ans)
            return s.index>t.index;
        return s.ans<t.ans;
    }
};
priority_queue<pp,vector<pp>,cmp> q;
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        while(!q.empty()) q.pop();
        for(int i=1;i<=n;i++)
        {
            a[i].index=i;
            scanf("%d",&a[i].ans);
            a[i].ans-=i;
            q.push(a[i]);
        }
        for(int i=1;i<=n;i++)
            scanf("%d",&b[i]);
        memset(w,0,sizeof(w));
        for(int i=1;i<=n;i++)
            w[b[i]]++;
        LL sum=0;
        int pos=n;
        int d_m=0;
        while(1)
        {
            pp T_T=q.top();
            q.pop();
            LL num=0;
            if(T_T.index<=d_m)  continue;
            else
            {
                for(int i=d_m+1;i<=T_T.index;i++)
                    num+=w[i];
                d_m=T_T.index;
            }
            sum+=(num*T_T.ans)%mod;
            sum%=mod;
            pp x_s;
            x_s.index=pos+1;
            x_s.ans=T_T.ans-pos-1;
            q.push(x_s);
            pos+=num;
            if(pos==2*n) break;
        }
        printf("%lld\n",sum);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值