Problem:
Problem F: Coupling
Problem
愛津大学では毎年大規模な合コンが行われています。
今年は
N
人の男性と
M
人の女性が参加します。
それぞれ男性は0から順に
N
−1までIDが割り振られおり、女性は0から順に
M
−1までIDが割り振られています。
この合コンでは自分の「大好きな人」と「そこそこ好きな人」のIDを提示します。
男性はそれぞれ女性のIDを、女性はそれぞれ男性のIDを提示します。
その後、以下のルールに従ってカップルが成立します。
男性は複数の女性、女性は複数の男性とカップルになってはいけない。
互いに「大好きな人」と提示した男性と女性でペアができる。
そこから、任意のペアを選びカップルを作ることができる。
片方が「大好きな人」、もう片方が「そこそこ好きな人」と提示した男性と女性でペアができる。
そこから、任意のペアを選びカップルを作ることができる。
互いに「そこそこ好きな人」と提示した男性と女性でペアができる。
そこから、任意のペアを選びカップルを作ることができる。
ルール2で出来たカップル、ルール3で出来たカップル、ルール4で出来たカップルの順にカップルの数が最大になるようにカップルが成立する。
サジ君はこの合コンの主催者です。
近年では参加者の数が多くなり手動でカップルの数を把握するのが大変になってきました。そこでプログラマーであるあなたは、サジ君の手伝いをすることにしました。上記のルールに従ってカップルを作った時の「大好きな人」同士のカップルの数と「大好きな人」と「そこそこ好きな人」によるカップルの数と「そこそこ好きな人」同士のカップルの数を出力するプログラムを作成してください。
Input
入力は以下の形式で与えられる。
N
M
L1
a
1
b
1
a
2
b
2
:
a
L1
b
L1
L2
c
1
d
1
c
2
d
2
:
c
L2
d
L2
L3
e
1
f
1
e
2
f
2
:
e
L3
f
L3
L4
g
1
h
1
g
2
h
2
:
g
L4
h
L4
1行目にそれぞれ男性の参加者の数と女性の参加者の数を表す2つの整数
N
,
M
が与えられる。次に男性側の大好きな人を表すデータの数
L1
が与えられる。続くL1行に
a
i
と
b
i
が空白区切りで与えられる。それぞれ、ID
a
i
の男性がID
b
i
の女性を「大好き」であることを示す。
続く行に男性側のそこそこ好きな人を表すデータの数
L2
が与えられる。続くL2行に
c
i
と
d
i
が空白区切りで与えられる。それぞれ、ID
c
i
の男性がID
d
i
の女性を「そこそこ好き」であることを示す。次に女性側の大好きな人を表すデータの数
L3
が与えられる。続くL3行に
e
i
と
f
i
が空白区切りで与えられる。それぞれ、ID
e
i
の女性がIDの
f
i
の男性を「大好き」であることを示す。
続く行に女性側のそこそこ好きな人を表すデータの数
L4
が与えられる。続くL4行に
g
i
と
h
i
が空白区切りで与えられる。それぞれ、ID
g
i
の女性がID
h
i
の男性を「そこそこ好き」であることを示す。
Constraints
入力は以下の条件を満たす。
1 ≤
N
,
M
≤ 100
0 ≤
a
i
,
c
i
,
f
i
,
h
i
≤
N
−1
0 ≤
b
i
,
d
i
,
e
i
,
g
i
≤
M
−1
0 ≤
L1
,
L2
,
L3
,
L4
≤ 2000
L1
> 0,
L2
> 0 において (
a
i
,
b
i
) ≠ (
c
j
,
d
j
) ( 0 ≤
i
<
L1
, 0 ≤
j
<
L2
)
L3
> 0,
L4
> 0 において (
e
i
,
f
i
) ≠ (
g
j
,
h
j
) ( 0 ≤
i
<
L3
, 0 ≤
j
<
L4
)
(
a
i
,
b
i
) ≠ (
a
j
,
b
j
) (
i
≠
j
)　( 0 ≤
i
<
L1
, 0 ≤
j
<
L1
)
(
c
i
,
d
i
) ≠ (
c
j
,
d
j
) (
i
≠
j
)　( 0 ≤
i
<
L2
, 0 ≤
j
<
L2
)
(
e
i
,
f
i
) ≠ (
e
j
,
f
j
) (
i
≠
j
)　( 0 ≤
i
<
L3
, 0 ≤
j
<
L3
)
(
g
i
,
h
i
) ≠ (
g
j
,
h
j
) (
i
≠
j
)　( 0 ≤
i
<
L4
, 0 ≤
j
<
L4
)
Output
問題文のルールに従ってカップルが成立した時の、「大好きな人」同士のペアの数と「大好きな人」と「そこそこ好きな人」のペアの数と「そこそこ好き」同士のペアの数を空白区切りで1行に出力せよ。
Sample Input 1
3 3
3
0 0
1 1
2 2
2
1 0
2 1
3
1 1
2 2
0 1
2
1 0
2 0
Sample Output 1
2 0 0
この場合男性1と女性1、男性2と女性2が大好き同士でカップルとなり「大好き同士」のペア数が2になる。
すると、男性0のことが「大好き」な女性も「そこそこ好き」な女性もいなくなってしまいます。
また、女性0のことが「大好き」な男性も「そこそこ好き」な男性もいなくなってしまうため以降カップルは成立しなくなります。
Sample input 2
5 5
5
4 1
2 2
1 4
1 3
4 2
5
1 1
1 2
3 3
3 0
3 4
5
2 3
2 2
0 3
0 2
4 1
5
2 0
4 0
1 0
4 3
2 1
Sample Output2
2 1 0

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;

#define repl(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define rep(i,n) repl(i,0,n)
#define dbg(x) cout<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()

typedef pair<int,int> P;
typedef pair<P,int> PI;
#define fi first
#define se second

#define INF INT_MAX/3
#define MAX_V 300

struct edge{
  int to,cap,cost,rev;
};

int V;
vector<edge> G[MAX_V];
int h[MAX_V];
int dist[MAX_V];
int prevv[MAX_V],preve[MAX_V];

void init(int v){
  V=v;
  for(int i=0;i<MAX_V;i++){
    G[i].clear();
  }
}

void add_edge(int from,int to,int cap,int cost){
  //printf("%d -> %d : %d\n", from,to,cap);
  G[from].push_back((edge){to,cap,cost,(int)G[to].size()});
  G[to].push_back((edge){from,0,-cost,(int)G[from].size()-1});
}

int min_cost_flow(int s,int t,int f){
  int res=0;
  memset(h,0,sizeof(h));
  while(f>0){
    fill(dist,dist+V,INF);
    dist[s]=0;
    bool update=true;
    while(update){
      update=false;
      for(int v=0;v<V;v++){
        if(dist[v]==INF)continue;
        for(int i=0;i<(int)G[v].size();i++){
          edge &e=G[v][i];
          if(e.cap>0&&dist[e.to]>dist[v]+e.cost){
            dist[e.to]=dist[v]+e.cost;
            prevv[e.to]=v;
            preve[e.to]=i;
            update=true;
          }
        }
      }
    }
    if(dist[t]==INF)return INF;

    int d=f;
    for(int v=t;v!=s;v=prevv[v]){
      d=min(d,G[prevv[v]][preve[v]].cap);
    }
    f-=d;
    res+=d*dist[t];
    for(int v=t;v!=s;v=prevv[v]){
      edge &e=G[prevv[v]][preve[v]];
      e.cap-=d;
      G[v][e.rev].cap+=d;
    }
  }
  return res;
}

int N,M;
int g[2][303][303];

int main(){
  cin>>N>>M;
  rep(x,2)rep(y,2){
    int L;
    cin>>L;
    rep(i,L){
      int a,b;
      cin>>a>>b;
      if(x==0) g[y][a][b]++;
      else g[y][b][a]++;
    }
  }

  int source=N+M,sink=N+M+1;

  PI res=PI(P(0,0),0);
  repl(f,1,min(N,M)+1){
    init(N+M+2);

    rep(i,N)add_edge(source,i,1,0);
    rep(i,M)add_edge(N+i,sink,1,0);

    rep(i,N)rep(j,M){
      if(g[0][i][j]==2){
        add_edge(i,N+j,1,-30000);
      }else if(g[0][i][j]==1&&g[1][i][j]==1){
        add_edge(i,N+j,1,-200);
      }else if(g[1][i][j]==2){
        add_edge(i,N+j,1,-1);
      }
    }

    int m=-min_cost_flow(source,sink,f);
    int resa=m/30000;
    int resb=(m-resa*30000)/200;
    int resc=(m-resa*30000-resb*200);
    res=max(res,PI(P(resa,resb),resc));
  }

  cout<<res.fi.fi<<" "<<res.fi.se<<" "<<res.se<<endl;
}
accuracy: 1
time_ms: 70
memory_kb: 3468
final_rank: 6

code_snippet: #include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)

using namespace std;
/*
typedef long long ll;
typedef pair<ll,int> ii;
 
struct Edge{
  int to; ll cap; ll cost; int rev;
  Edge(int to=0,int cap=0,ll cost=0,int rev=0):to(to),cap(cap),cost(cost),rev(rev){}
};
 
const int MAX_V = 1100; const ll IINF = LLONG_MAX;
int V;
vector<Edge> G[MAX_V];
ll h[MAX_V],dist[MAX_V]; int prevv[MAX_V],preve[MAX_V];
 
inline void add_edge(int from,int to,int cap,ll cost){
  G[from].push_back(Edge(to,cap,cost,G[to].size()));
  G[to].push_back(Edge(from,0,-cost,G[from].size()-1));
}
 

ll min_cost_flow(int s,int t){
  ll res = 0;
  while(1){
    fill(dist,dist+V,IINF);
    dist[s] = 0;
    bool update = true;
    while( update ){
      update = false;
      rep(v,V){
        if( dist[v] == IINF ) continue;
        rep(i,(int)G[v].size()){
          Edge &e = G[v][i];
          if( e.cap > 0LL && dist[e.to] > dist[v] + e.cost ){
            dist[e.to] = dist[v] + e.cost;
            prevv[e.to] = v;
            preve[e.to] = i;
            update = true;
          }
        }
      }
    }

    if( dist[t] == IINF ) break;
 
    ll d = IINF;
    for(int v=t;v!=s;v=prevv[v]) d = min(d,G[prevv[v]][preve[v]].cap);
    if( d == 0LL ) break;

    res += d * dist[t];
    for(int v=t;v!=s;v=prevv[v]){
      Edge &e = G[prevv[v]][preve[v]];
      e.cap -= d;
      G[v][e.rev].cap += d;
    }
  }
  return res;
}
*/
typedef long long ll;
typedef pair<ll,int> ii;


struct Edge{
  int to; ll cap,cost; int rev;
  Edge(int to=0,ll cap=0,ll cost=0,int rev=0):to(to),cap(cap),cost(cost),rev(rev){}
};

const int MAX_V = 1100; ll IINF = LLONG_MAX;
int V;
vector<Edge> G[MAX_V];
ll h[MAX_V],dist[MAX_V]; int prevv[MAX_V],preve[MAX_V];

inline void add_edge(int from,int to,ll cap,ll cost){
  G[from].push_back(Edge(to,cap,cost,G[to].size()));
  G[to].push_back(Edge(from,0,-cost,G[from].size()-1));
}

ll min_cost_flow(int s,int t){
  ll res = 0;
  fill(h,h+V,0);
  while(1){
    priority_queue<ii,vector<ii>,greater<ii> > Q;
    fill(dist,dist+V,IINF);
    dist[s] = 0;
    Q.push(ii(0,s));
    while(!Q.empty()){
      ii p = Q.top(); Q.pop();
      int v = p.second;
      if( dist[v] < p.first ) continue;
      for(int i=0;i<G[v].size();i++){
        Edge &e = G[v][i];
        if( e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to] ) { 
          dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
          prevv[e.to] = v;
          preve[e.to] = i;
          Q.push(ii(dist[e.to],e.to));
        }
      }
    }
    //if( dist[t] == IINF ) break;
    rep(v,V) h[v] += dist[v];
    if( h[t] >= 0LL ) break;
    ll d = IINF;
    for(int v=t;v!=s;v=prevv[v]) d = min(d,G[prevv[v]][preve[v]].cap);
    res += d * h[t];
    for(int v=t;v!=s;v=prevv[v]){
      Edge &e = G[prevv[v]][preve[v]];
      e.cap -= d;
      G[v][e.rev].cap += d;
    }
  }
  return res;
}


int N,M;

int main(){
  cin >> N >> M;

  int source = N+M;
  int sink = source + 1;
  V = sink + 1;
  rep(i,N) add_edge(source,i,1,0);
  rep(i,M) add_edge(N+i,sink,1,0);
  
  set<ii> S[2];
  int L,a,b;
  cin >> L;
  rep(i,L) { cin >> a >> b; S[0].insert(ii(a,b)); }
  cin >> L;
  rep(i,L) { cin >> a >> b; S[1].insert(ii(a,b)); }
  cin >> L;
  rep(i,L) {
    cin >> a >> b;
    if( S[0].count(ii(b,a)) ) add_edge(b,N+a,1,-1000000000LL);
    if( S[1].count(ii(b,a)) ) add_edge(b,N+a,1,-1000000LL);
  }
  cin >> L;
  rep(i,L) {
    cin >> a >> b;
    if( S[0].count(ii(b,a)) ) add_edge(b,N+a,1,-1000000LL);
    if( S[1].count(ii(b,a)) ) add_edge(b,N+a,1,-1000LL);
  }
  ll res = -1 * min_cost_flow(source,sink);
    cout << res/1000000000LL << " "
       << res/1000000LL%1000LL << " "
       << res/1000LL%1000LL << endl;
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1588
final_rank: 1

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i = 0; i < int(n); i++)
#define all(c) (c).begin(), (c).end()
using namespace std;

struct MinCostFlow{
    struct edge{int to,cap,rev,cost;};
    vector<vector<edge>> G;
    vector<int> dist,pv,pe;
    int size;

    static const int MAX_C = 1000000000;

    MinCostFlow(int size):G(size),dist(size),pv(size),pe(size),size(size){}

    void add_edge(int from, int to, int cap, int cost){
        //printf("%d --> %d , %d\n",from,to,cost);
        G[from].push_back({to, cap, (int)G[to].size(), cost});
        G[to].push_back({from, 0, (int)G[from].size() - 1, -cost});
    }

    //impossible f ? -1 : result
    int min_cost_flow(int s, int t, int f){
        int res = 0;
        while(f > 0){
            fill(begin(dist),end(dist),MAX_C);
            dist[s] = 0;
            bool upd = true;
            while(upd){
                upd = false;
                for(int v = 0; v < size; v++){
                    if(dist[v] == MAX_C) continue;
                    for(int i = 0; i < (int)G[v].size(); i++){
                        edge &e = G[v][i];
                        if(e.cap > 0 && dist[e.to] > dist[v] + e.cost){
                            dist[e.to] = dist[v] + e.cost;
                            pv[e.to] = v;
                            pe[e.to] = i;
                            upd = true;
                        }
                    }
                }
            }

            if(dist[t] == MAX_C){
                //impossible f
                return -1;
            }

            int d = f;
            for(int v = t; v != s; v = pv[v]){
                d = min(d, G[pv[v]][pe[v]].cap);
            }

            f -= d;
            res += d * dist[t];

            for(int v = t; v != s; v = pv[v]){
                edge &e = G[pv[v]][pe[v]];
                e.cap -= d;
                G[v][e.rev].cap += d;
            }
        }
        return res;
    }
};

const int X = 500;

struct Ans{
    int a,b,c;
    Ans(int x):a(x%X),b(x%(X*X)/X),c(x/(X*X)){
        assert(x >= 0);
    }
};

int G[100][100];

void fill_G(int x, bool rev){
    int l,a,b;
    cin >> l;
    rep(i,l){
        cin >> a >> b;
        (rev ? G[b][a] : G[a][b]) += x;
    }
}

int main(){
    int n,m;
    cin >> n >> m;

    fill_G(5,false);
    fill_G(1,false);
    fill_G(5,true);
    fill_G(1,true);

    MinCostFlow mcf(300);
    const int S = 298, T = 299;

    rep(i,n) rep(j,m){
        if(G[i][j] == 10) mcf.add_edge(i,j+100,1,1);
        else if(G[i][j] == 6) mcf.add_edge(i,j+100,1,X);
        else if(G[i][j] == 2) mcf.add_edge(i,j+100,1,X * X);
    }

    rep(i,n) mcf.add_edge(S,i,1,0);
    rep(j,m) mcf.add_edge(j+100,T,1,0);

    Ans ans(0);
    bool upd = false;
    for(int i = 1000; i >= 1; i--){
        MinCostFlow tmp = mcf;
        int res = tmp.min_cost_flow(S,T,i);
        if(res >= 0){
            Ans x(res);
            if((x.a > ans.a) || (x.a == ans.a && x.b > ans.b) || (x.a == ans.a && x.b == ans.b && x.c > ans.c)){
                ans = x;
                upd = true;
            }
        }
    }
    assert(upd);
    cout << ans.a << " " << ans.b << " " << ans.c << endl;
}
accuracy: 0.07407407407407407
time_ms: 40
memory_kb: 1260
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define REP(i,n) for(int i=0;i<(int)(n);++i)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define ALL(c) (c).begin(), (c).end()
#define valid(y,x,h,w) (0<=y&&y<h&&0<=x&&x<w)
#define tpl(...) make_tuple(__VA_ARGS__)
const int INF = 0x3f3f3f3f;
const double EPS = 1e-8;
const double PI = acos(-1);
typedef long long ll;
typedef pair<int,int> pii;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } return 0; }
template<class T>ostream&operator<<(ostream &o,const vector<T>&t){o<<'[';FOR(i,t){if(i!=t.begin())o<<',';o<<*i;}return o<<']';}
template<class S,class T>ostream&operator<<(ostream &o,const pair<S,T>&t){return o<<'('<<t.first<<','<<t.second<<')';}
template<int N,class Tp>void output(ostream&,const Tp&){}
template<int N,class Tp,class,class ...Ts>void output(ostream &o,const Tp&t){if(N)o<<',';o<<get<N>(t);output<N+1,Tp,Ts...>(o,t);}
template<class ...Ts>ostream&operator<<(ostream&o,const tuple<Ts...>&t){o<<'(';output<0,tuple<Ts...>,Ts...>(o,t);return o<<')';}
template<class T>void output(T t,char z=10){if(t<0)t=-t,putchar(45);int c[20];
int k=0;while(t)c[k++]=t%10,t/=10;for(k||(c[k++]=0);k;)putchar(c[--k]^48);putchar(z);}
template<class T>void outputs(T t){output(t);}
template<class S,class ...T>void outputs(S a,T...t){output(a,32);outputs(t...);}
template<class T>void output(T *a,int n){REP(i,n)output(a[i],i!=n-1?',':10);}
template<class T>void output(T *a,int n,int m){REP(i,n)output(a[i],m);}
template<class T>bool input(T &t){int n=1,c;for(t=0;!isdigit(c=getchar())&&~c&&c-45;);
if(!~c)return 0;for(c-45&&(n=0,t=c^48);isdigit(c=getchar());)t=10*t+c-48;t=n?-t:t;return 1;}
template<class S,class ...T>bool input(S&a,T&...t){input(a);return input(t...);}

const int MAX_V = 100000;
const int MAX_E = 100000;
// T : define {T+T, T<T, int*T}
template<class T> 
struct MinCostFlow {
  struct Edge {
    int s,t,cap;
    T cost;
    int next;
    Edge(){}
    Edge(int s, int t, int cap, T cost, int next) : s(s),t(t),cap(cap),cost(cost),next(next) {}
  };
  int n;
  Edge edge[MAX_E+10];
  int head[MAX_V+10];
  int cnt;
  void add_edge(int s, int t, int cap, T cost) {
    edge[cnt] = Edge(s,t,cap,cost,head[s]); head[s] = cnt++;
    edge[cnt] = Edge(t,s,0,-cost,head[t]); head[t] = cnt++;
  }
  T zero, inf;
  void init(int _n, T _zero, T _inf) {
    n = _n;
    REP(i,n) head[i] = 0;
    zero = _zero;
    inf = _inf;
    cnt = 2;
  }
  T dis[MAX_V];
  int inQ[MAX_V],pre[MAX_V];
  bool spfa(int s, int t) {
    queue<int> Q;
    REP(i,n) dis[i] = inf, inQ[i] = 0;
    for (dis[s]=zero,inQ[s]=1,Q.push(s); !Q.empty(); ) {
      int v = Q.front(); Q.pop();
      inQ[v] = 0;
      for (int k=head[v]; k; k=edge[k].next) {
        int u = edge[k].t;
        if (edge[k].cap && chmin(dis[u],dis[v]+edge[k].cost)) {
          pre[u] = k;
          if (!inQ[u]) inQ[u] = 1, Q.push(u);
        }
      }
    }
    return dis[t] < inf;
  }
  T minCost;
  pair<T,int> run(int s, int t, int F=INF) {
    pair<T,int> res(zero, 0);
    minCost = zero;
    while(F&&spfa(s,t)) {
      int f = F;
      for (int v=t; v!=s; v=edge[pre[v]].s)
        chmin(f, edge[pre[v]].cap);
      for (int v=t; v!=s; v=edge[pre[v]].s) {
        res.first += edge[pre[v]].cost * f;
        edge[pre[v]].cap -= f;
        edge[pre[v]^1].cap += f;
      }
      F -= f;
      res.second += f;
      chmin(minCost, res.first);
    }
    return res;
  }
};

template<class T, int N>
struct Vector {
  T v[N];
  int n;
  T& operator[](int i) { return v[i]; }
  const T operator[](int i) const { return v[i]; }
  Vector() : n(0) {}
  Vector(int n) : n(n) { REP(i,n)v[i]=0; }
  Vector(const initializer_list<T> &u) : n(0) { for(auto&i:u)v[n++]=i; }
  Vector(int n, const T &x) : n(n) { REP(i,n) v[i]=x; }
  Vector& operator+=(const Vector &u) { REP(i,n)v[i]+=u[i]; return *this; }
  Vector& operator-=(const Vector &u) { REP(i,n)v[i]-=u[i]; return *this; }
  Vector operator+(const Vector &u) const { return Vector(*this)+=u; }
  Vector operator-(const Vector &u) const { return Vector(*this)-=u; }
  Vector operator*=(const T &x) { REP(i,n)v[i]*=x; return *this; }
  Vector operator*(const T &x) const { return Vector(*this)*=x; }
  Vector operator-() const { Vector res(n); REP(i,n) res[i]=-v[i]; return res; }
  bool operator<(const Vector &u) const { REP(i,n) if (v[i]!=u[i]) return v[i]<u[i]; return 0; }
  // bool operator>(const Vector &u) const { return u<v; }
  bool operator==(const Vector &u) const { REP(i,n) if (v[i]!=u[i]) return 0; return 1;}
  friend ostream& operator<<(ostream &os, const Vector& v) { return os<<vector<T>{v.v,v.v+v.n}; }
};

typedef Vector<int,3> Vec;

int g1[100][100];
int g2[100][100];
int g3[100][100];
int g4[100][100];

void inp(int g[100][100]) {
  int L;
  cin >> L;
  REP(i,L) {
    int a,b;
    input(a,b);
    g[a][b] = 1;
  }
}

int main() {
  int n,m;
  while(input(n,m)) {
    REP(i,n)REP(j,n) {
      g1[i][j]=g2[i][j]=g3[i][j]=g4[i][j]=0;
    }
    inp(g1);
    inp(g2);
    inp(g3);
    inp(g4);
    static MinCostFlow<Vec> mcf;
    mcf.init(n+m+2, {0,0,0}, {INF,INF,INF});
    REP(i,n) REP(j,m) {
      if (g1[i][j] && g3[j][i]) {
        mcf.add_edge(i, n+j, 1, {-1,0,0});
      } else if (g1[i][j] && g4[j][i] || g2[i][j] && g3[j][i]) {
        mcf.add_edge(i, n+j, 1, {0,-1,0});
      } else if (g2[i][j] && g4[j][i]) {
        mcf.add_edge(i, n+j, 1, {0,0,-1});
      }
    }
    REP(i,n) mcf.add_edge(n+m,i,1,{0,0,0});
    REP(i,m) mcf.add_edge(n+i,n+m+1,1,{0,0,0});
    mcf.run(n+m,n+m+1);
    Vec cost = mcf.minCost;
    // cout << cost << endl;
    outputs(-cost[0], -cost[1], -cost[2]);
  }
}
accuracy: 1
time_ms: 10
memory_kb: 6400
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define REP(i,n) for(int i=0;i<(int)(n);++i)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define ALL(c) (c).begin(), (c).end()
#define valid(y,x,h,w) (0<=y&&y<h&&0<=x&&x<w)
#define tpl(...) make_tuple(__VA_ARGS__)
const int INF = 0x3f3f3f3f;
const double EPS = 1e-8;
const double PI = acos(-1);
typedef long long ll;
typedef pair<int,int> pii;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }
template<class T>ostream&operator<<(ostream &o,const vector<T>&t){o<<'[';FOR(i,t){if(i!=t.begin())o<<',';o<<*i;}return o<<']';}
template<class S,class T>ostream&operator<<(ostream &o,const pair<S,T>&t){return o<<'('<<t.first<<','<<t.second<<')';}
template<int N,class Tp>void output(ostream&,const Tp&){}
template<int N,class Tp,class,class ...Ts>void output(ostream &o,const Tp&t){if(N)o<<',';o<<get<N>(t);output<N+1,Tp,Ts...>(o,t);}
template<class ...Ts>ostream&operator<<(ostream&o,const tuple<Ts...>&t){o<<'(';output<0,tuple<Ts...>,Ts...>(o,t);return o<<')';}
template<class T>void output(T t,char z=10){if(t<0)t=-t,putchar(45);int c[20];
int k=0;while(t)c[k++]=t%10,t/=10;for(k||(c[k++]=0);k;)putchar(c[--k]^48);putchar(z);}
template<class T>void outputs(T t){output(t);}
template<class S,class ...T>void outputs(S a,T...t){output(a,32);outputs(t...);}
template<class T>void output(T *a,int n){REP(i,n)output(a[i],i!=n-1?',':10);}
template<class T>void output(T *a,int n,int m){REP(i,n)output(a[i],m);}
template<class T>bool input(T &t){int n=1,c;for(t=0;!isdigit(c=getchar())&&~c&&c-45;);
if(!~c)return 0;for(c-45&&(n=0,t=c^48);isdigit(c=getchar());)t=10*t+c-48;t=n?-t:t;return 1;}
template<class S,class ...T>bool input(S&a,T&...t){input(a);return input(t...);}

typedef valarray<int> Weight;
template<class T>ostream&operator<<(ostream &o,const valarray<T>&t){o<<'[';
  REP(i,t.size()) {if(i!=0)o<<',';o<<t[i];}return o<<']';}

struct Edge {
  int src, dst;
  int capacity;
  Weight cost;
  Edge(int src, int dst, int capacity, Weight cost) :
    src(src), dst(dst), capacity(capacity), cost(cost) { }
};
bool operator<(const Weight &u, const Weight &v) {
  REP(i,u.size()) if (u[i] != v[i]) return u[i] < v[i];
  return 0;
}

bool operator < (const Edge &e, const Edge &f) {
  return f.cost < e.cost;
}

typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

typedef vector<Weight> Array;
typedef vector<Array> Matrix;

void add_edge(Graph &g, int s, int d, int cap, Weight cost) {
  g[s].push_back(Edge(s,d,cap,cost));
  g[d].push_back(Edge(d,s,0,-cost));
}

#define RESIDUE(u,v) (capacity[u][v] - flow[u][v])
#define RCOST(u,v) (cost[u][v] + h[u] - h[v])

// Dijkstr
Weight minimumCostFlow(const Graph &g, int s, int t) {
  const int n = g.size();
  vector<vector<int> > capacity(n, vector<int>(n)), flow(n, vector<int>(n));
  Matrix cost(n, Array(n, {0,0,0}));
  REP(u,n) FOR(e,g[u]) {
    capacity[e->src][e->dst] += e->capacity;
    cost[e->src][e->dst] += e->cost;
  }
  pair<Weight, int> total(Weight{0,0,0},0); // (cost, flow)
  Weight res({0,0,0});
  vector<Weight> h(n, {INF,INF,INF});
  h[s] = {0,0,0};
  // ベルマンフォードでポテンシャルを求めて負辺に対応
  REP(k, n) REP(i, n) FOR(e,g[i]) if (capacity[e->src][e->dst]) {
    if (Weight(h[e->src] + cost[e->src][e->dst]) < h[e->dst])
      h[e->dst] = h[e->src] + cost[e->src][e->dst];
  }
  for (int F = INF; F > 0; ) { // residual flow
    vector<Weight> d(n, {INF,INF,INF}); d[s] = 0;
    vector<int> p(n, -1);
    priority_queue<Edge> Q;
    for (Q.push(Edge(-2, s, 0, Weight({0,0,0}))); !Q.empty(); ) {
      Edge e = Q.top(); Q.pop();
      if (p[e.dst] != -1) continue;
      p[e.dst] = e.src;
      FOR(f, g[e.dst]) if (RESIDUE(f->src, f->dst) > 0) {
        if (Weight(d[f->src] + RCOST(f->src, f->dst)) < d[f->dst]) {
          d[f->dst] = d[f->src] + RCOST(f->src, f->dst);
          Q.push( Edge(f->src, f->dst, 0, d[f->dst]) );
        }
      }
    }
    // cout << d << endl;
    // cout << p << endl;
    if (p[t] == -1) break;    
    int f = F;
    for (int u = t; u != s; u = p[u])
      f = min(f, RESIDUE(p[u], u));
    for (int u = t; u != s; u = p[u]) {
      total.first += f * cost[p[u]][u];
      flow[p[u]][u] += f; flow[u][p[u]] -= f;
    }
    if (total.first < res) {
      res = total.first;
    }
    F -= f;
    total.second += f;
    REP(u, n) if (h[u] < Weight({INF,INF,INF})) h[u] += d[u]; // ifいらない？
  }
  return res;
}

int g1[100][100];
int g2[100][100];
int g3[100][100];
int g4[100][100];

void inp(int g[100][100]) {
  int L;
  cin >> L;
  REP(i,L) {
    int a,b;
    input(a,b);
    g[a][b] = 1;
  }
}

int main() {
  int n,m;
  while(input(n,m)) {
    REP(i,n)REP(j,n) {
      g1[i][j]=g2[i][j]=g3[i][j]=g4[i][j]=0;
    }
    inp(g1);
    inp(g2);
    inp(g3);
    inp(g4);
    Graph g(n+m+2);
    REP(i,n) REP(j,m) {
      if (g1[i][j] && g3[j][i]) {
        add_edge(g, i, n+j, 1, Weight({-1,0,0}));
      } else if (g1[i][j] && g4[j][i] || g2[i][j] && g3[j][i]) {
        add_edge(g, i, n+j, 1, Weight({0,-1,0}));
      } else if (g2[i][j] && g4[j][i]) {
        add_edge(g, i, n+j, 1, Weight({0,0,-1}));
      }
    }
    REP(i,n) add_edge(g,n+m,i,1,{0,0,0});
    REP(i,m) add_edge(g,n+i,n+m+1,1,{0,0,0});
    Weight cost = minimumCostFlow(g,n+m,n+m+1);
    // cout << cost << endl;
    outputs(-cost[0], -cost[1], -cost[2]);
  }
}
accuracy: 1
time_ms: 30
memory_kb: 3636
final_rank: 4

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <sstream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <numeric>
#include <cctype>
#include <tuple>
#include <array>
#include <climits>
#include <bitset>

// BEGIN CUT HERE
#ifdef _MSC_VER
#include <agents.h>
#endif
// END CUT HERE 

#define FOR(i, a, b) for(int i = (a); i < (int)(b); ++i)
#define rep(i, n) FOR(i, 0, n)
#define ALL(v) v.begin(), v.end()
#define REV(v) v.rbegin(), v.rend()
#define MEMSET(v, s) memset(v, s, sizeof(v))
#define MP make_pair
#define MT make_tuple

using namespace std;

typedef long long ll;
typedef pair<ll, ll> P;

struct Cost{
	vector<int> val;
	Cost(){
		val.assign(4, 0);
	}
	Cost(initializer_list<int> il){
		val = il;
	}

	bool operator < (const Cost &rhs)const{
		return val > rhs.val;
	}

	Cost operator-() const{
		Cost res = *this;
		for (auto &e : res.val) e = -e;
		return res;
	}

	Cost& operator=(Cost rhs){
		val = rhs.val;
		return *this;
	}

	Cost operator+(const Cost &rhs) const {
		Cost res = *this;
		for (int i = 0; i < 4; i++) res.val[i] += rhs.val[i];
		return res;
	}

	Cost operator-(const Cost &rhs) const {
		return *this + -rhs;
	}

	Cost operator*(const int &x) const {
		Cost res = *this;
		for (int i = 0; i < 4; i++) res.val[i] *= x;
		return res;
	}

	bool operator==(const Cost &rhs) const{
		return val == rhs.val;
	}
};

const Cost ZERO = { 0, 0, 0, 0 };
const Cost INF = { -10000, 0, 0, 0 };

struct MinCostFlow{
	struct edge{
		int to, rev, cap;
		Cost cost;
		edge(int to, Cost cost, int rev, int cap) :to(to), cost(cost), rev(rev), cap(cap){}
	};

	int n;
	vector<vector<edge>> G;

	void add(int from, int to, Cost cost, int cap){
		G[from].push_back(edge(to, cost, G[to].size(), cap));
		G[to].push_back(edge(from, -cost, G[from].size() - 1, 0));
	}
	vector<Cost> dist, h;
	vector<int> prevv, preve;

	MinCostFlow(int size){
		n = size;
		G.assign(n, vector<edge>());
		dist.assign(n, ZERO);
		h.assign(n, ZERO);
		prevv.assign(n, 0);
		preve.assign(n, 0);
	}

	Cost min_cost_flow(int s, int t, int f){
		Cost res = ZERO;
		rep(i, n) h[i] = ZERO;
		while (f){
			rep(i, n) dist[i] = INF;
			dist[s] = ZERO;
			priority_queue<pair<Cost, int>, vector<pair<Cost, int>>, greater<pair<Cost, int>> > q;
			q.push(MP(ZERO, s));
			while (!q.empty()){
				int pos = q.top().second;
				Cost d = q.top().first;
				q.pop();

				if (dist[pos] < d) continue;

				rep(i, G[pos].size()){
					edge &e = G[pos][i];
					if (e.cap <= 0) continue;
					if (dist[pos] + e.cost + h[pos] - h[e.to] < dist[e.to]){
						dist[e.to] = dist[pos] + e.cost + h[pos] - h[e.to];
						prevv[e.to] = pos;
						preve[e.to] = i;
						q.push(MP(dist[e.to], e.to));
					}
				}

			}

			if (dist[t] == INF) return INF;

			rep(i, n) h[i] = h[i] + dist[i];

			int d = f;
			for (int v = t; v != s; v = prevv[v]){
				d = min(d, G[prevv[v]][preve[v]].cap);
			}
			f -= d;
			res = res + h[t]*d;
			for (int v = t; v != s; v = prevv[v]){
				edge &e = G[prevv[v]][preve[v]];
				e.cap -= d;
				G[e.to][e.rev].cap += d;
			}
		}

		return res;
	}
};

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

	int n, m;
	cin >> n >> m;
	vector<vector<int>> mat(n+m, vector<int>(n+m));
	int L1, L2, L3, L4;
	cin >> L1;
	while (L1--){
		int a, b;
		cin >> a >> b;
		mat[a][n+b] = 2;
	}
	cin >> L2;
	while (L2--){
		int a, b;
		cin >> a >> b;
		mat[a][n+b] = 1;
	}
	cin >> L3;
	while (L3--){
		int a, b;
		cin >> a >> b;
		mat[n+a][b] = 2;
	}
	cin >> L4;
	while (L4--){
		int a, b;
		cin >> a >> b;
		mat[n+a][b] = 1;
	}

	MinCostFlow mcf(n+m+2);
	int SRC = n + m, SNK = SRC + 1;
	mcf.add(SRC, SNK, {0, 0, 0, 1}, 100);

	rep(i, n) mcf.add(SRC, i, ZERO, 1);
	FOR(j, n, n + m) mcf.add(j, SNK, ZERO, 1);

	rep(i, n) FOR(j, n, n+m){
		Cost cost;
		if (mat[i][j]*mat[j][i] == 4){
			cost.val[0] = 1;
		}
		else if (mat[i][j]*mat[j][i] == 2){
			cost.val[1] = 1;
		}
		else if (mat[i][j]*mat[j][i] == 1){
			cost.val[2] = 1;
		}
		else{
			continue;
		}
		mcf.add(i, j, cost, 1);
	}

	Cost res = mcf.min_cost_flow(SRC, SNK, 100);

	vector<int> ans = res.val;
	rep(i, 3) cout << (i ? " " : "") << ans[i];
	cout << endl;


	return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 1792
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long weight;
typedef pair<weight, int> P;

struct edge {
  int to;
  int cap;
  weight cost;
  int rev;
  edge(int to_, int cap_, weight cost_, int rev_):to(to_), cap(cap_), cost(cost_), rev(rev_) {}
};

constexpr weight INF = (1ll << 55);

vector<vector<edge>> G;

void init(int V) {
  G.assign(V, vector<edge>());
}

void add_edge(int from, int to, int cap, weight cost) {
  G[from].emplace_back(to, cap, cost, G[to].size());
  G[to].emplace_back(from, 0, -cost, G[from].size() - 1);
}

weight min_cost_flow(int s, int t, int f) {
  const int n = G.size();
  weight res = 0;
  vector<int> prevv(n), preve(n);
  vector<weight> h(n, 0);

  while(f > 0) {
    priority_queue<P, vector<P>, greater<P>> que;
    vector<weight> dist(n, INF);
    dist[s] = 0;
    que.push({0, s});

    while(!que.empty()) {
      const auto d = que.top().first;
      const auto v = que.top().second;
      que.pop();

      if(dist[v] < d) continue;

      for(unsigned i = 0; i < G[v].size(); ++i) {
	const edge &e = G[v][i];
	if(e.cap > 0 && dist[e.to] > d + e.cost + h[v] - h[e.to]) {
	  dist[e.to] = d + e.cost + h[v] - h[e.to];
	  prevv[e.to] = v;
	  preve[e.to] = i;
	  que.push({dist[e.to], e.to});
	}
      }
    }

    if(dist[t] == INF) return -1;

    for(int v = 0; v < n; ++v) {
      h[v] += dist[v];
    }

    int d = f;
    for(int v = t; v != s; v = prevv[v]) {
      d = min(d, G[prevv[v]][preve[v]].cap);
    }

    f -= d;
    res += d * h[t];
    for(int v = t; v != s; v = prevv[v]) {
      edge &e = G[prevv[v]][preve[v]];
      e.cap -= d;
      G[v][e.rev].cap += d;
    }
  }

  return res;
}

constexpr weight DD = 1000000;
constexpr weight DS = 1000;
constexpr weight SS = 1;

inline void input(vector<vector<int>> &like, int v) {
  int l;
  cin >> l;

  for(int i = 0; i < l; ++i) {
    int a, b;
    cin >> a >> b;
    like[a][b] = v;
  }
}

int main() {
  int n, m;
  cin >> n >> m;

  vector<vector<int>> like_m(n, vector<int>(m, 0));
  vector<vector<int>> like_f(m, vector<int>(n, 0));

  input(like_m, 2);
  input(like_m, 1);
  input(like_f, 2);
  input(like_f, 1);

  const int source = n + m;
  const int sink = source + 1;
  init(sink + 1);

  for(int i = 0; i < n; ++i) {
    add_edge(source, i, 1, 0);
  }

  for(int i = 0; i < m; ++i) {
    add_edge(i + n, sink, 1, 0);
  }

  for(int i = 0; i < n; ++i) {
    for(int j = 0; j < m; ++j) {
      if(like_m[i][j] && like_f[j][i]) {
	const int sum = like_m[i][j] + like_f[j][i];
	switch(sum) {
	case 4: add_edge(i, j + n, 1, -DD); break;
	case 3: add_edge(i, j + n, 1, -DS); break;
	case 2: add_edge(i, j + n, 1, -SS); break;
	default: assert(false);
	}
      }
      else {
	add_edge(i, j + n, 1, 0);
      }
    }
  }

  const weight ans = -min_cost_flow(source, sink, min(n, m));
  const long long dd = ans / DD;
  const long long ds = ans % DD / DS;
  const long long ss = ans % DS;

  cout << dd << " " << ds << " " << ss << endl;

  return EXIT_SUCCESS;
}
accuracy: 1
time_ms: 10
memory_kb: 1944
final_rank: 2