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
#include
#include
#include
#include
#include
#include
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.ansvector,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);
    }
}

你可能感兴趣的:(ACM竞赛,【含有数学思想】,【含有一定思考】,ACM的进程)