結果
問題 |
No.3201 Corporate Synergy
|
ユーザー |
![]() |
提出日時 | 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 |
ソースコード
#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(); }