其实就是贪心,每次都选左标记最小这样可以包括更多的数;可以看出选取最大值的这段区间是一直向右移动,这样可以用单调队列来计算最大值。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;

typedef long long ll;
const int maxn=250005;
ll a[maxn*2],fac[maxn*2],p=1e9+7;
ll id[maxn*2],um[maxn*2];

multiset<int> cnt;

int main(){
    int n,b;
    while(scanf("%d",&n)==1){
        cnt.clear();
        for(int i=1;i<=n;i++)    scanf("%lld",a+i);
        for(int i=0;i<n;i++){
            scanf("%d",&b);
            cnt.insert(b);
        }
        for(int i=1;i<=n;i++)    fac[i]=a[i]-i;
        int cur=1;
        id[0]=1;
        um[0]=fac[1];
        for(int i=2;i<=n;i++){
            while(fac[i]>=um[cur-1]&&cur!=0){
                cur--;
            }
            um[cur]=fac[i];
            id[cur]=i;
            cur++;
        }
        int idx=0;
        for(int i=n+1;i<=2*n;i++){
            int k=*cnt.begin();
            cnt.erase(cnt.begin());
            while(k>id[idx]){
                idx++;
            }
            a[i]=um[idx];
            fac[i]=a[i]-i;
            while(fac[i]>=um[cur-1]&&cur!=idx){
                cur--;
            }
            um[cur]=fac[i];
            id[cur]=i;
            cur++;
        }
        ll sum=0;
        for(int i=n+1;i<=2*n;i++){
            sum=(sum+a[i])%p;
        }
        printf("%lld\n",sum);
    }
    return 0;
}

 

posted on 2017-07-28 10:57  mutinner  阅读(108)  评论(0)    收藏  举报