其实就是贪心,每次都选左标记最小这样可以包括更多的数;可以看出选取最大值的这段区间是一直向右移动,这样可以用单调队列来计算最大值。
#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; }
浙公网安备 33010602011771号