51nod 1053 最大M子段和 V2
阿新 • • 發佈:2019-01-25
題意就是讓你選擇m段不想交的區間使的和最大,hk比賽的時候遇到的,當時不會做,後來大佬說是上古原題,51nod上找到了,我們首先預處理區間,把區間變成正負相替的區間,然後開始刪區間,使得剩下的區間個數為m個,我們現在有兩個選擇,可以選擇刪一個正數區間,使得兩個負數區間相連,或者刪除一個負數區間,使得相鄰的兩個正數區間相連。每次刪除的時候都要刪除能刪除的裡面的最小值,所以我們可以用一個set維護絕對值,從小到大的刪,用連結串列維護前驅和後驅
#include<bits/stdc++.h> using namespace std; using LL = int64_t; const int maxn=1e5+5; const LL mod=1e9+7; const int INF=1e9; const LL LLINF=1e14; const double pi=acos(-1.0); LL a[maxn],pre[maxn],nxt[maxn]; set<pair<LL,int>>st; void _erase(int x) { int l=pre[x],r=nxt[x]; if(l) nxt[l]=r; if(r) pre[r]=l; } int main() { ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); int n,m;cin>>n>>m; LL sum=0,num=1,cnt=0,res=0; for(int i=1;i<=n;i++) { LL x;cin>>x; if(x>0&&sum<0) { a[num++]=sum; sum=x; } else if(x<0&&sum>0) { a[num++]=sum; sum=x; } else sum+=x; } if(sum!=0) a[num++]=sum; for(int i=1;i<num;i++) { pre[i]=i-1,nxt[i]=i+1; st.insert({abs(a[i]),i}); if(a[i]>0) cnt++,res+=a[i]; } nxt[num-1]=0; while(cnt>m) { int id=(*st.begin()).second; st.erase(st.begin()); if((a[id]<0&&(pre[id]==0||nxt[id]==0))||a[id]==0) continue; st.erase({abs(a[pre[id]]),pre[id]}); st.erase({abs(a[nxt[id]]),nxt[id]}); res-=abs(a[id]); a[id]=a[id]+a[pre[id]]+a[nxt[id]]; _erase(pre[id]); _erase(nxt[id]); st.insert({abs(a[id]),id}); cnt--; } cout<<res; return 0; }