D-Armchairs 最小費用流で辺の張り方を工夫 (交差しない二部マッチング)

f:id:peroon:20210516201625p:plain

#include <atcoder/mincostflow>
using namespace atcoder; // 忘れがち

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);

    // input
    ll N;
    cin>>N;

    VI A(N);
    rep(i, N) cin >> A[i];

    VI O,Z;
    rep(i,N){
      if(A[i]==0){
        Z.push_back(i);
      }else{
        O.push_back(i);
      }
    } 

    ll start=N;
    ll goal=N+1;
    mcf_graph<int, long long> g(N+2);

    for(ll o : O){
      g.add_edge(start,o,1,0);
    }
    
    // 愚直に1から0へ辺を張る。絶対に不要な辺を削ってもTLE...
    // ll diff = SZ(Z)-SZ(O);
    // rep(i,SZ(O)){
    //   FOR(j,i,SZ(Z)){
    //     if(j-i>diff)break;
    //     g.add_edge(O[i],Z[j],1,abs(O[i]-Z[j]));
    //   }
    // }

    // こうすると辺の数がO(N)になる!
    rep(i,N-1){
      g.add_edge(i,i+1,1e9,1); // ここのコスト1がabs(A[i]-A[j])に対応している!
      g.add_edge(i+1,i,1e9,1);
    }

    for(ll z : Z){
      g.add_edge(z,goal,1,0);
    }
    auto result = g.flow(start,goal,SZ(O));
    ll cost = result.second;
    p(cost);

    return 0;
}