Problem:
Problem J: Demon's Plan
BackGround
デーモンズプランでは慾を司る108体の悪魔が日夜プログラミングコンテストでしのぎを削っている。主催であるパトローンは、全ての慾が集う場所”リクス＝マグナ”に悪魔たちを招待しようとしている。
    パトローンはまだ招待を送っていない悪魔に招待を送りたいが、悪魔は世界各地におり、自分で行くのは面倒くさいので自身の使い魔達にやらせることにした。
    パトローンは気が利くので使い魔同士がより平等に働くようにどの使い魔がどの悪魔を担当するかを割り振ろうとしている。
Problem
N
体の使い魔と
M
体の悪魔がいる。
    使い魔
i
と 悪魔
j
の距離は
H
i j
である。
各悪魔に必ず1人の使い魔を向かわせたい。どの使い魔がどの悪魔を訪問するかは以下の条件に従って割り振ることにした。
使い魔1体あたりの訪問する悪魔の数の差の最大を最小化する。
1を満たした上で訪問する悪魔と担当する使い魔の距離の最大を最小化する。
1行目に使い魔1体あたりの訪問する悪魔の数の差の最大を、2行目に悪魔と担当する使い魔の距離の最大を出力せよ。
Input
入力は以下の形式で与えられる。
N
M
H
0 0
H
0 1
…
H
0 M−1
H
1 0
H
1 1
…
H
1 M−1
.
.
H
N−1 0
H
N−1 1
…
H
N−1 M−1
1行目に使い魔の数
N
と悪魔の数
M
が整数で空白区切りで与えられる。
    続く
N
行に使い魔と悪魔の距離が整数で与えられる。
H
ij
は使い魔
i
と悪魔
j
の距離を表す。
Constraints
1 ≤
N
≤ 108
1 ≤
M
≤ 108
1 ≤
H
i j
≤ 10
9
( 0 ≤
i
<
N
, 0 ≤
j
<
M
) ( 使い魔
i
から悪魔
j
までの距離 )
Output
問題文の条件に従い、1行目に使い魔1体あたりの訪問する悪魔の数の差の最大を、2行目に悪魔と担当する使い魔の距離の最大を出力せよ。
Sample Input 1
3 3
1 2 3
2 1 2
3 2 1
Sample Output 1
0
1
使い魔
0
- 悪魔
0
使い魔
1
- 悪魔
1
使い魔
2
- 悪魔
2
と割り振ることで訪問する悪魔の数の差が0になり、担当使い魔と悪魔の距離の最大が1になり最適な組み合わせになる。
Sample Input 2
3 5
1 2 3 4 5
5 4 3 2 1
4 3 2 1 5
Sample Output 2
1
2
使い魔
0
- 悪魔
0
使い魔
0
- 悪魔
1
使い魔
1
- 悪魔
4
使い魔
2
- 悪魔
3
使い魔
2
- 悪魔
2
と割り振ることで訪問する悪魔の差が1になり、担当使い魔と悪魔の距離の最大が2になり最適な組み合わせになる。

Submitted solutions:

code_snippet: #include<iostream>
#include<vector>
#include<string>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<utility>
#include<set>
#include<map>
#include<stack>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int> P;
typedef pair<ll, ll> LP;
typedef vector<int> vec;
typedef long double ld;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define stop char nyaa;cin>>nyaa;


int max_n;
const int mn = 100000;

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

struct MinCostFlow {
	vector<edge> G[mn];
	int par[mn];
	int dist[mn];
	void add_edge(int from, int to, int cap, int cost) {
		G[from].push_back({ to,cap,cost,(int)G[to].size() });
		G[to].push_back({ from, 0, -cost, (int)G[from].size() - 1 });
		max_n = max({ max_n, from + 1, to + 1 });
	}

	int minimum_road(int s, int t) {
		fill(par, par + max_n, -1);
		fill(dist, dist + max_n, mod);
		dist[s] = 0;
		priority_queue<P, vector<P>, greater<P>> q; q.push({ 0,s });
		while (q.size()) {
			P p = q.top(); q.pop();
			int id = p.second;
			if (id == t)continue;
			if (p.first > dist[id])continue;
			rep(j, G[id].size()) {
				if (G[id][j].cap > 0) {
					int to = G[id][j].to;
					int nd = p.first + G[id][j].cost;
					if (nd < dist[to]) {
						dist[to] = nd;
						par[to] = id;
						q.push({ dist[to],to });
					}
				}
			}
		}
		int cur = t;
		while (cur != s) {
			int p = par[cur];
			if (p < 0)return -1;
			rep(j, G[p].size()) {
				if (G[p][j].cap > 0 && G[p][j].to == cur && dist[p] + G[p][j].cost == dist[cur]) {
					G[p][j].cap--;
					G[cur][G[p][j].rev].cap++;
				}
			}
			cur = p;
		}
		return dist[t];
	}
	int minimum_cost_flow(int s, int t, int k) {
		int ret = 0;
		rep(i, k) {
			int z = minimum_road(s, t);
			if (z < 0)return -1;
			ret += z;
		}
		return ret;
	}
};


 void solve() {
	int n, m;
	cin >> n >> m;
	int d[111][111];
	rep(i, n)rep(j, m)cin >> d[i][j];
	int c1 = m / n, c2 = !!(m%n);
	int ok = 1e9, ng = 0;
	while (ok - ng > 1) {
		int mid = (ok + ng) / 2;
		MinCostFlow mc;
		int s = m + n, t = m + n + 1;
		rep(i, n)rep(j, m) {
			if (d[i][j] <= mid) {
				mc.add_edge(i, n + j, 1, 0);
			}
		}
		rep(i, n) {
			mc.add_edge(s, i, c1, 0);
			mc.add_edge(s, i, c2, 1);
		}
		rep(i, m) {
			mc.add_edge(n + i, t, 1, 0);
		}
		int ret = mc.minimum_cost_flow(s, t, m);
		if (ret == m % n)ok = mid;
		else ng = mid;
	}
	cout << c2 << endl;
	cout << ok << endl;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	//cout << fixed << setprecision(6);
	solve();
	//stop
		return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 5736
final_rank: 4

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

typedef long long  Weight;
struct Edge {
	int src, dest;
	int cap, rev;
	Weight weight;
	bool operator < (const Edge &rhs) const { return weight > rhs.weight; }
};

const int V = 4000;
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;
Weight h[V];                //??????????????£???
Weight dist[V];             //???????????¢
int prevv[V], preve[V];  //??´???????????¨??????

void add_edge(Graph &g, int src, int dest, int cap, Weight weight) {
	g[src].push_back(Edge{ src, dest, cap, (int)g[dest].size(), weight });
	g[dest].push_back(Edge{ dest, src, 0, (int)g[src].size() - 1, -weight });
}
#define REP(i,n) for(int i=0;i<(int)n;++i)
#define FOR(i,c) for(auto i=(c).begin();i!=(c).end();++i)
#define ALL(c) (c).begin(), (c).end()
const Weight INF = 2147483647;
const Weight ZERO=0;
//????????????double?????????eps?????????
Weight min_cost_flow(Graph &g, int s, int t, int f) {
	Weight res = ZERO;
	memset(h, ZERO, sizeof(h));
	typedef pair<Weight, int> P;
	while (f > 0) {
		priority_queue<P, vector<P>, greater<P> > que;
		fill(dist, dist + V, INF);
		dist[s] = 0;
		que.push(P(ZERO, s));
		while (!que.empty()) {
			P p = que.top(); que.pop();
			const int v = p.second;
			if (dist[v] < p.first) continue;
			REP(i, g[v].size()) {
				Edge &e = g[v][i];
				if (e.cap > 0 && dist[e.dest] > dist[v] + e.weight + h[v] - h[e.dest]) {
					dist[e.dest] = dist[v] + e.weight + h[v] - h[e.dest];
					prevv[e.dest] = v;
					preve[e.dest] = i;
					que.push(P(dist[e.dest], e.dest));
				}
			}
		}
		if (dist[t] == INF) return -1;
		REP(v, V) h[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 = 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 norma ;
int amari ;
bool check(const int dis, const vector<vector<int>>&diss) {
	const int start=0;
	const int tukai0=start+1;
	const int tukai1=tukai0+N;
	const int akuma=tukai1+N;
	const int goal=akuma+M;
	Graph g(goal+1);
	for (int i = 0; i < N; ++i) {

		add_edge(g, start, tukai0 + i, 108, 0);
	}
	for (int i = 0; i < N; ++i) {
		add_edge(g,tukai0+i,tukai1+i,norma,0);
		add_edge(g,tukai0+i,tukai1+i,1,1);
	}
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < M; ++j) {
			if (diss[i][j] <= dis) {
				add_edge(g,tukai1+i,akuma+j,1,0);
			}
		}
	}
	for (int j = 0; j < M; ++j) {
		add_edge(g,akuma+j,goal,1,0);
	}
	auto p(min_cost_flow(g,start,goal,M));
	if(p==-1)return false;
	return p<=amari;
}
int main() { cin >> N >> M;
	vector<vector<int>>diss(N,vector<int>(M));
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < M; ++j) {
			cin>>diss[i][j];
		}
	}
	norma=M/N;
	amari = M-(M/N)*N;
	int al=0;
	int ar=1e9;
	while (al + 1 != ar) {
		int am((al+ar+1)/2);
		if (check(am, diss)) {
			ar=am;
		}else{
			al=am;
		}
	}
	if(amari==0)cout<<0<<endl;
	else cout<<1<<endl;
	cout<<ar<<endl;
	
	return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 3496
final_rank: 3

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

typedef int Weight;
typedef int Capacity;
struct Edge {
	int src, dst; Capacity cap;
	Edge(int s, int d, Capacity c) : src(s), dst(d), cap(c) {}
};
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

struct Dinic {
	int n, s, t;
	vector<int> level, prog, que;
	vector<vector<Capacity> > cap, flow;
	vector<vector<int> > g;
	Capacity inf;
	Dinic() {}
	Dinic(const Graph &graph)
		: n(graph.size()),
		cap(n, vector<Capacity>(n)), flow(n, vector<Capacity>(n)),
		g(n, vector<int>()), inf((int)1e9) {
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < graph[i].size(); j++) {
				const Edge& e = graph[i][j];
				int u = e.src, v = e.dst;
				Capacity c = e.cap;
				add_edge(u, v, c);
			}
		}
	}
	Dinic(int n_) : n(n_), cap(n, vector<Capacity>(n)), flow(n, vector<Capacity>(n)),
		g(n, vector<int>()), inf((int)1e9) {
	}
	void add_edge(int u, int v, Capacity c) {
		cap[u][v] += c; cap[v][u] += c; flow[v][u] += c;
		g[u].push_back(v); g[v].push_back(u);
	}
	void reset() {
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < n; j++) {
				cap[i][j] = flow[i][j] = 0;
			}
			g[i].clear();
		}
	}
	inline Capacity residue(int u, int v) { return cap[u][v] - flow[u][v]; }
	Capacity solve(int s_, int t_) {
		this->t = t_, this->s = s_;
		que.resize(n + 1);
		Capacity res = 0;
		while(levelize()) { prog.assign(n, 0); res += augment(s, inf); }
		return res;
	}
	bool levelize() {
		int l = 0, r = 0;
		level.assign(n, -1); level[s] = 0; que[r++] = s;
		while(l != r) {
			int v = que[l++]; if(v == t) break;
			for(int i = 0; i < g[v].size(); i++) {
				const int& d = g[v][i];
				if(level[d] == -1 && residue(v, d) != 0) {
					level[d] = level[v] + 1; que[r++] = d;
				}
			}
		}
		return level[t] != -1;
	}
	Capacity augment(int v, Capacity lim) {
		Capacity res = 0;
		if(v == t) return lim;
		for(int &i = prog[v]; i < (int)g[v].size(); i++) {
			const int &d = g[v][i];
			if(residue(v, d) == 0 || level[v] >= level[d]) continue;
			const Capacity aug = augment(d, min(lim, residue(v, d)));
			flow[v][d] += aug; flow[d][v] -= aug;
			res += aug; lim -= aug;
			if(lim == 0) break;
		}
		return res;
	}
};

int N, M;
int H[110][110];
int a1[110], a2[110];
int b[110];

bool check(int x) {
	Dinic d(2 * N + M + 4);
	int s1 = 2 * N + M, s2 = s1 + 1, S = s2 + 1, T = S + 1;
	d.add_edge(S, s1, M - M % N);
	d.add_edge(S, s2, M % N);
	for(int i = 0; i < N; i++) {
		d.add_edge(s1, a1[i], M / N);
		d.add_edge(s2, a2[i], 1);
	}
	for(int i = 0; i < N; i++) {
		for(int j = 0; j < M; j++) {
			if(H[i][j] <= x) {
				d.add_edge(a1[i], b[j], 1);
				d.add_edge(a2[i], b[j], 1);
			}
		}
	}
	for(int i = 0; i < M; i++) {
		d.add_edge(b[i], T, 1);
	}
	return d.solve(S, T) == M;
}


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

	cin >> N >> M;
	for(int i = 0; i < N; i++) {
		for(int j = 0; j < M; j++) {
			cin >> H[i][j];
		}
	}

	int n = 0;
	for(int i = 0; i < N; i++) {
		a1[i] = n++;
		a2[i] = n++;
	}
	for(int i = 0; i < M; i++) {
		b[i] = n++;
	}

	int diff = M % N == 0 ? 0 : 1;
	int ng = 0, ok = 1e9;
	while(abs(ng - ok) / 2) {
		int mid = (ng + ok) / 2;
		if(check(mid)) ok = mid;
		else ng = mid;
	}
	cout << diff << endl;
	cout << ok << endl;
}
accuracy: 1
time_ms: 10
memory_kb: 3896
final_rank: 1

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

#define int long long

#define rep(i,n) for(int i=0;i<(n);i++)
#define all(v) (v).begin(),(v).end()
#define pb push_back
#define fi first
#define se second

typedef vector<int>vint;
typedef pair<int,int>pint;
typedef vector<pint>vpint;

template<typename A,typename B>inline void chmin(A &a,B b){if(a>b)a=b;}
template<typename A,typename B>inline void chmax(A &a,B b){if(a<b)a=b;}

int N,M;
int H[111][111];

struct edge{
    int to,cap,cost,rev;
    edge(int a,int b,int c,int d):to(a),cap(b),cost(c),rev(d){}
};

const int INF=1001001001;

const int MV=300;
int src=MV-2,snk=MV-1;
vector<edge>G[MV];
int dist[MV];
int prevv[MV],preve[MV];

void init(){
    rep(i,MV)G[i].clear();
}

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

int min_cost_flow(int s,int t,int f){
    int res=0;
    while(f>0){
        fill(dist,dist+MV,INF);
        dist[s]=0;
        bool update=true;
        while(update){
            update=false;
            for(int v=0;v<MV;v++){
                if(dist[v]==INF)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){
                        dist[e.to]=dist[v]+e.cost;
                        prevv[e.to]=v;
                        preve[e.to]=i;
                        update=true;
                    }
                }
            }
        }
        if(dist[t]==INF)return -1;
        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;
}

bool C(int x){
    int t=M/N;
    init();
    rep(i,N)add_edge(src,i,t,0);
    rep(i,N)add_edge(src,i,1,1);

    rep(i,N)rep(j,M)if(H[i][j]<=x)add_edge(i,j+N,1,0);
    rep(i,M)add_edge(i+N,snk,1,0);

    int tmp=min_cost_flow(src,snk,M);
    if(tmp==-1)return false;
    if(tmp>M%N)return false;
    return true;
}

signed main(){
    cin>>N>>M;
    rep(i,N)rep(j,M)cin>>H[i][j];

    int lb=0,ub=1001001001;
    while(ub-lb>1){
        int mid=(ub+lb)/2;
        if(C(mid))ub=mid;
        else lb=mid;
    }
    cout<<(M%N!=0)<<endl;
    cout<<ub<<endl;
    return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 3544
final_rank: 2

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

#define int long long

#define rep(i,n) for(int i=0;i<(n);i++)
#define all(v) (v).begin(),(v).end()
#define pb push_back
#define fi first
#define se second

typedef vector<int>vint;
typedef pair<int,int>pint;
typedef vector<pint>vpint;

template<typename A,typename B>inline void chmin(A &a,B b){if(a>b)a=b;}
template<typename A,typename B>inline void chmax(A &a,B b){if(a<b)a=b;}

int N,M;
int H[111][111];

struct edge{
    int to,cap,cost,rev;
    edge(int a,int b,int c,int d):to(a),cap(b),cost(c),rev(d){}
};

const int INF=1001001001;

const int MV=300;
int src=MV-2,snk=MV-1;
vector<edge>G[MV];
int dist[MV];
int prevv[MV],preve[MV];

void init(){
    rep(i,MV)G[i].clear();
}

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

int min_cost_flow(int s,int t,int f){
    int res=0;
    while(f>0){
        fill(dist,dist+MV,INF);
        dist[s]=0;
        bool update=true;
        while(update){
            update=false;
            for(int v=0;v<MV;v++){
                if(dist[v]==INF)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){
                        dist[e.to]=dist[v]+e.cost;
                        prevv[e.to]=v;
                        preve[e.to]=i;
                        update=true;
                    }
                }
            }
        }
        if(dist[t]==INF)return -1;
        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;
}

bool C(int x){
    int t=M/N;
    init();
    rep(i,N)add_edge(src,i,t,0);
    rep(i,N)add_edge(src,i,1,1);

    rep(i,N)rep(j,M)if(H[i][j]<=x)add_edge(i,j+N,1,0);
    rep(i,M)add_edge(i+N,snk,1,0);

    return min_cost_flow(src,snk,M)!=-1;
}

signed main(){
    cin>>N>>M;
    rep(i,N)rep(j,M)cin>>H[i][j];

    int lb=0,ub=1001001001;
    while(ub-lb>1){
        int mid=(ub+lb)/2;
        if(C(mid))ub=mid;
        else lb=mid;
    }
    cout<<(M%N!=0)<<endl;
    cout<<ub<<endl;
    return 0;
}
accuracy: 0.3235294117647059
time_ms: 50
memory_kb: 3496
final_rank: 5