結果

問題 No.3201 Corporate Synergy
ユーザー Today03
提出日時 2025-07-12 14:19:11
言語 C++23
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 3 ms / 2,000 ms
コード長 6,397 bytes
コンパイル時間 4,317 ms
コンパイル使用メモリ 295,412 KB
実行使用メモリ 7,848 KB
最終ジャッジ日時 2025-07-12 14:19:17
合計ジャッジ時間 5,244 ms
ジャッジサーバーID
(参考情報)
judge2 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other AC * 20
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
using namespace std;
#define ALL(x) (x).begin(),(x).end()
#define REP(i, n) for(ll i=0; i<(ll)(n); i++)
#define PER(i, n) for(ll i=(ll)(n)-1; i>=0; i--)

template<typename T> int LB(const vector<T>& v, T x) { return lower_bound(ALL(v),x)-v.begin(); }
template<typename T> int UQ(T& v) { sort(ALL(v)); v.erase(unique(ALL(v)),v.end()); return v.size(); }
template<typename T> bool chmax(T &a, T b) { return a<b ? a=b, true : false; }
template<typename T> bool chmin(T &a, T b) { return a>b ? a=b, true : false; }
template<typename T> using rpriority_queue = priority_queue<T,vector<T>,greater<T>>;
using ll=long long; const int INF=1e9+10; const ll INFL=4e18;
using ld=long double; using lll=__int128_t; using ull=unsigned long long;
using VI=vector<int>; using VVI=vector<VI>; using VL=vector<ll>; using VVL=vector<VL>;
using PL=pair<ll,ll>; using VP=vector<PL>; using WG=vector<vector<pair<int,ll>>>;


#ifdef LOCAL
#include "./debug.hpp"
#else
#define debug(...)
#define print_line
#endif



/// @brief 最大流
struct MaxFlow {
    /// @brief 辺構造体
    struct Edge {
        int from; ///< 始点
        int to; ///< 終点
        int rev; ///< 逆辺のインデックス
        ll cap; ///< 容量
        ll flow; ///< 流量
        bool isrev;
        Edge(int from, int to, ll cap, int rev, bool isrev): from(from),to(to),rev(rev),cap(cap),flow(0),isrev(isrev) {}
    };

    MaxFlow(int n): graph(n), level(n), iter(n) {}
    MaxFlow()=default;

    /// @brief 容量 cap の辺を追加する
    void add_edge(int from, int to, ll cap) {
        graph[from].push_back(Edge(from,to,cap,graph[to].size(),false));
        graph[to].push_back(Edge(to,from,0,graph[from].size()-1,true));
    }

private:
    vector<vector<Edge>> graph;
    vector<int> level,iter;
    void bfs(int s) {
        fill(level.begin(),level.end(),-1);
        queue<int> que;
        level[s]=0;
        que.push(s);
        while(!que.empty()) {
            int v=que.front();
            que.pop();
            for(auto &e:graph[v]) {
                if(e.cap>0&&level[e.to]<0) {
                    level[e.to]=level[v]+1;
                    que.push(e.to);
                }
            }
        }
    }
    ll dfs(int v, int t, ll f) {
        if(v==t) return f;
        for(int& i=iter[v]; i<(int)graph[v].size(); i++) {
            auto& e=graph[v][i];
            if(e.cap>0&&level[v]<level[e.to]) {
                ll d=dfs(e.to,t,min(f,e.cap));
                if(d>0) {
                    e.cap-=d,graph[e.to][e.rev].cap+=d;
                    e.flow+=d,graph[e.to][e.rev].flow-=d;
                    return d;
                }
            }
        }
        return 0;
    }

public:
    /// @brief s から t への最大流を求める
    /// @note O(V^2 E)
    ll flow(int s, int t) {
        ll ret=0;
        while(true) {
            bfs(s);
            if(level[t]==-1) return ret;
            fill(iter.begin(),iter.end(),0);
            ll f;
            while((f=dfs(s,t,INFL))>0) ret+=f;
        }
    }

    /// @brief 直前に流したフローから最小カットを復元する
    /// @brief 始点 v から到達可能か否か
    vector<int> mincut(int v=0) {
        vector<int> ret(graph.size());
        queue<int> que;
        que.push(v);
        ret[v]=true;
        while(!que.empty()) {
            int v=que.front();
            que.pop();
            for(auto& e:graph[v]) {
                if(e.cap>0&&!ret[e.to]) {
                    ret[e.to]=true;
                    que.push(e.to);
                }
            }
        }
        return ret;
    }

    /// @brief 直前に流したフローの辺の情報を返す
    vector<Edge> get_edges() {
        vector<Edge> ret;
        for(int i=0; i<graph.size(); i++) for(auto &e:graph[i]) if(!e.isrev) ret.push_back(e);
        return ret;
    }
};


/// @brief 燃やす埋める
struct MoyasuUmeru {
    MoyasuUmeru(int n) {
        this->n=n;
        start=n;
        goal=n+1;
        mf=MaxFlow(n+2);
    }

    /// @brief x[i] = 0 のときコスト zero, x[i] = 1 のときコスト one がかかるという条件を追加する
    void add_single(int i, ll zero, ll one) {
        if(zero<=one) {
            //基本コストがzeroで、iを0から1に変えると+one-zeroされる
            offset+=zero;
            mf.add_edge(start,i,one-zero);
        } else {
            //基本コストがoneで、iを1から0に変えると-one+zeroされる
            offset+=one;
            mf.add_edge(i,goal,zero-one);
        }
    }

    /**
     * @brief
     * x[ i ], x[ j ] の組み合わせについて、以下のコストかかるという条件を追加する
     * |          | x[j] = 0 | x[j] = 1 |
     * | ---      | ---      | ---      |
     * | x[i] = 0 | a        | b        |
     * | x[i] = 1 | c        | d        |
     * 
     * @attention b + c >= a + d を要求する
    */
    void add_double(int i, int j, ll a, ll b, ll c, ll d) {
        assert(b+c>=a+d);
        offset+=a;
        add_single(i,0,c-a);
        add_single(j,0,d-c);
        mf.add_edge(i,j,b+c-a-d);
    }

    vector<int> fukugen() {
        auto ret=mf.mincut(n+1);
        ret.pop_back(); ret.pop_back();
        return ret;
    }

    /// @brief コスト最小値を求める
    ll solve() { return mf.flow(start,goal)+offset; }

private:
    int n,start,goal;
    ll offset=0;
    MaxFlow mf;
};

//----------------------------------------------------------

void solve() {
    ll N; cin>>N;
    ll INFL=1e12;

    MoyasuUmeru mu(N);
    VL P(N);
    REP(i,N) {
        cin>>P[i];
        mu.add_single(i,0,-P[i]);
    }

    ll M; cin>>M;
    VP E(M);
    REP(i,M) {
        ll u,v; cin>>u>>v; u--; v--;
        mu.add_double(u,v,0,INFL,0,0);
        E[i]={u,v};
    }

    ll K; cin>>K;
    vector<tuple<ll,ll,ll>> sing(K);
    REP(i,K) {
        ll a,b,s; cin>>a>>b>>s; a--; b--;
        mu.add_double(a,b,0,0,0,-s);
        sing[i]={a,b,s};
    }

    cout<<-mu.solve()<<endl;

    /*auto kai=mu.fukugen();
    ll ans=0;
    REP(i,N) if(kai[i]) ans+=P[i];
    for(auto [a,b]: E) if(kai[b]) assert(kai[a]);
    for(auto [a,b,s]: sing) if(kai[a] && kai[b]) ans+=s;

    cout<<ans<<endl;*/
}

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr);
    //cout<<fixed<<setprecision(15);
    int T=1;
    //cin>>T;
    while(T--) solve();
}
0