結果
| 問題 |
No.3201 Corporate Synergy
|
| コンテスト | |
| ユーザー |
Today03
|
| 提出日時 | 2025-07-12 14:23:42 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 6,421 bytes |
| コンパイル時間 | 4,598 ms |
| コンパイル使用メモリ | 297,948 KB |
| 実行使用メモリ | 7,972 KB |
| 最終ジャッジ日時 | 2025-07-12 14:23:48 |
| 合計ジャッジ時間 | 4,915 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 19 WA * 1 |
ソースコード
#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()); ret[v]=true;
queue<int> que; que.push(v);
while(!que.empty()) {
int v=que.front(); que.pop();
for(auto& e:graph[v]) {
if(e.cap>0 && !ret[e.to] && !e.isrev) {
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(start);
ret.pop_back(); ret.pop_back();
for(int& x: ret) x^=1;
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};
}
mu.solve();
auto kai=mu.fukugen();
debug(kai);
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();
}
Today03