予鈴

アウトプットとメモ書きの中間みたいな記事がたくさん出ます。

D - 3N Numbers

D: 3N Numbers - AtCoder Beginner Contest 062 | AtCoder


以前解けなかった問題が、ヒントで解けるようになったので…
前半の要素Nと後半の要素Nの差を最大にすれば良い。


中間の要素(配列の添字だとn \sim 2n-1)を最適に選べば良い。
PriorityQueueを使って、前半N要素のうちの最小値と中間N要素を比較していく。(後半の場合も同じく)

ちなみに、
Submission #1735282 - AtCoder Beginner Contest 062 | AtCoder
こういう解法だと絶対に解けない。N要素全部前半にくっつけたほうが良い場合がある。
N が奇数の時、前半と後半の両方に含まれる場合があるんじゃないかと思ってたけど、そんなことはない。
(↑これでめっちゃ時間とかした。)


#include<bits/stdc++.h>
using ll =  long long;
#define int ll
#define ld long double
#define INF 1e9
#define EPS 0.0000000001
#define rep(i,n) for(int i=0;i<n;i++)
#define all(in) in.begin(), in.end()
template<class T, class S> void cmin(T &a, const S &b) { if (a > b)a = b; }
template<class T, class S> void cmax(T &a, const S &b) { if (a < b)a = b; }
#define MAX 9999999
using namespace std;
typedef pair<int, int> pii;
typedef pair<double,double>pdd;
signed main(){
    int n; cin>>n;
    vector<int>v(3*n);
    rep(i,3*n) cin>>v[i];
    priority_queue<int,vector<int>,greater<int>>lque;
    priority_queue<int,vector<int>>sque;
    int ls=0,ss=0;
    vector<int>lv;
    vector<int>sv;
    rep(i,n){
        lque.push(v[i]);
        sque.push(v[2*n+i]);
        ls+=v[i];
        ss+=v[2*n+i];
    }
    lv.push_back(ls);
    sv.push_back(ss);
    int ans=-INF*INF;
    cmax(ans,ls-ss);
    rep(i,n){
        lque.push(v[n+i]);
        sque.push(v[2*n-i-1]);
        ls+=v[n+i]-lque.top();
        ss+=v[2*n-i-1]-sque.top();
        lv.push_back(ls);
        sv.push_back(ss);
        sque.pop();
        lque.pop();
    }
    rep(i,lv.size())cmax(ans, lv[i]-sv[n-i]);
    cout<<ans<<endl;
}
 

lv[i] := i番目まで見たときの、前半の合計の最大値
sv[i]:= i番目まで見たときの、後半の合計の最小値
添字マジックには気をつけよう!