题解:CF182C Optimal Sum

· · 题解

题目传送门

题目大意

有一个长度为 n 的数列 a,可以对它进行最多 k 次操作,每次操作可以将一个数变为它的相反数,输出最后所有长度为 len 的数列的和的绝对值的最大值。

思路

根据贪心,我们发现对于一个长度为 len 的数列,要么把它的前 k 大正数变为相反数,要么把它的前 k 小负数变为相反数,这样保证最优。所以我们可以用 4multiset 分别维护当前在 len 区间内的前 k 大正数,区间内的其余正数,区间内的前 k 小负数,区间内的其余负数。

每次往后移动一位时,判断这一位数的正负,假定为正,那么把他与第一个 multiset 中的最小值比较,如果比它大,那么就把他加入第一个 multiset,否则加入第二个 multiset。否则,加入第二个。

删除同理,如果这个数原本在第一个 multiset 中,那么就把第二个 multiset 中的最大值加入第一个 multiset,否则直接从第二个 multiset 中删除即可。

注意删除前,一定要判断这个数是否在 multiset 中。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1010101;
ll n,len,k,a[N],sum1,sum2,sum,ans;
multiset<ll>st1,st2,st3,st4;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>len;
    for(int i=1;i<=n;i++)cin>>a[i];
    cin>>k;
    for(int i=1;i<=n;i++){
        sum=sum+a[i]-a[max(i-len,0ll)];
        if(k==0){
            if(i>=len)ans=max(ans,abs(sum));
            continue;
        }
        if(a[i]>=0){
            if(st1.size()<k)st1.insert(-a[i]),sum1+=a[i];
            else{
                if(-a[i]<=*st1.rbegin()){
                    sum1+=a[i];
                    sum1+=*st1.rbegin();
                    st3.insert(*st1.rbegin());
                    st1.erase(--st1.end());
                    st1.insert(-a[i]);
                }
                else st3.insert(-a[i]);
            }
        }
        if(a[i]<0){
            if(st2.size()<k)st2.insert(a[i]),sum2+=a[i];
            else{
                if(a[i]<=*st2.rbegin()){
                    sum2+=a[i];
                    sum2-=*st2.rbegin();
                    st4.insert(*st2.rbegin());
                    st2.erase(--st2.end());
                    st2.insert(a[i]);
                }
                else st4.insert(a[i]);
            }
        }
        if(a[max(i-len,0ll)]>=0&&i>len){
            if(st1.find(-a[i-len])!=st1.end()){
                st1.erase(st1.find(-a[i-len]));
                st1.insert(*st3.begin());
                sum1-=a[i-len];
                sum1-=*st3.begin();
                if(st3.begin()!=st3.end())st3.erase(st3.begin());
            }
            else if(st3.find(-a[i-len])!=st3.end())st3.erase(st3.find(-a[i-len]));
        }
        if(a[max(i-len,0ll)]<0&&i>len){
            if(st2.find(a[i-len])!=st2.end()){
                st2.erase(st2.find(a[i-len]));
                st2.insert(*st4.begin());
                sum2-=a[i-len];
                sum2+=*st4.begin();
                if(st4.begin()!=st4.end())st4.erase(st4.begin());
            }
            else if(st4.find(a[i-len])!=st4.end())st4.erase(st4.find(a[i-len]));
        }
        if(i>=len)ans=max(ans,max(abs(sum-2*sum1),abs(sum-2*sum2)));
    }
    cout<<ans;
    return 0;
}