hdu6047-贪心&思维-2017多校(2)-Maximum Sequence

http://acm.hdu.edu.cn/showproblem.php?pid=6047
1 给定你一个n长的数组a,和n长的数组b。
问你构造a数组的 下一个n长,
有一个限制。每一个 a[i]需要由 一个b[i]限制。
在 b[i]- i这个长度下,我们要求 a[i]为这个范围内 a[i]-i的最大值。
问你这个数组 n+1- 2*n 的所有 a[i]的和。
1 贪心啊,每次都把最大值放在前面,才方便让后面用到,然后就把b倒着排了一下(如果两个b达到的目的相同的话,就取大的那一个。因为更小意味着更大的范围qwq)。然后就跑。
t了。
2 后来觉得是 查找b的时候有问题,我是每一个b 都跑一遍,找极值的。后来用倍增st维护了一下,把后i个先默认为最大的a来确定的。还是t。
3 st对每一个b 对应的区间的极值的查询都是O(1)的时间复杂度,坑死了,竟然不对,后来比赛完听大佬们的讲解,最大值最大值维护一下就行了,不用倍增st。还是T。
4 我终于意识到了是我对每个b进行判断本身构成了O(n2),又看见大佬说用单调队列或优先队列什么的,于是就看了博客。。。
用优先队列的思想,每次蹦出最大值。
同时维护新增数组 的 值,如果蹦出来的 没有新增数组的大,
那么结果必然在新增数组里,这个时候我就要把 这个 b留给下一个用而不是白白的用!!!这点很重!,wa了两次。
思维还是 too young

#include <bits/stdc++.h>
using namespace std;
const int MAXN=250006*2;
const int mod=1e9+7;
typedef long long ll;
int a[MAXN];
int b[MAXN];
bool vis[MAXN];
int n;
int m;
int main()
{  int ans;
    int maxx=-1;
    int mmax[MAXN];
    while(~scanf("%d",&n)){
    maxx=-1;
    memset(mmax,0,sizeof(mmax));
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        maxx=max(maxx,a[i]-i);
        a[i]-=i;
    }
    mmax[n+1]=0;
    for(int i=n;i>=1;i--)
         mmax[i]=max(mmax[i+1],a[i]);
    priority_queue<int>q;
    for(int i=0;i<n;i++){
        scanf("%d",&b[i]);
        q.push(mmax[b[i]]);
    }
    int temp=0;//维护最大值。
    ll ans=0;
     for(int i=n+1;i<=2*n;i++){
          if(q.top()>temp)
             {a[i]=q.top();q.pop();}
          else
            a[i]=temp;
            temp=max(a[i]-i,temp);
          ans+=1ll*a[i]%mod;
          a[i]-=i;
          //cout<<a[i]<<endl;
     }
     printf("%lld\n",ans%mod);
    }
    return 0;
}
或者不用优先队列,,直接贪心。
优先队列的意思是直接找出 弹出b的最大值。
但是我们发现这个规律也是确定的,
排序后,b[0]肯定是最大的,因为后面的数不可能比他大。依次#include <bits/stdc++.h>
using namespace std;
const int MAXN=250006*2;
const int mod=1e9+7;
typedef long long ll;
int a[MAXN];
int b[MAXN];
bool vis[MAXN];
int n;
int m;
int main()
{  int ans;
    int maxx=-1;
    int mmax[MAXN];
    while(~scanf("%d",&n)){
    maxx=-1;
    memset(mmax,0,sizeof(mmax));
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        maxx=max(maxx,a[i]);
        a[i]-=i;

    }
    mmax[n+1]=0;
    for(int i=n;i>=1;i--)
         mmax[i]=max(mmax[i+1],a[i]);
    for(int i=0;i<n;i++){
        scanf("%d",&b[i]);
    }
    sort(b,b+n);
    int temp=mmax[b[0]]-(n+1);//维护最大值。
    ll ans=mmax[b[0]];
//cout<<temp<<" "<<mmax[b[0]]<<endl;
     for(int i=1;i<n;i++){
         int tt=max(mmax[b[i]],temp);
         //cout<<mmax[b[i]]<<endl;
         //cout<<i<<" "<<mmax[b[i]]<<" "<<temp<<endl;
         //temp=
         ans+=1ll*tt%mod;
     }


     printf("%lld\n",ans%mod);
    }
    return 0;
},用双端队列也可以,但是我不太懂。。






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值