Problem:
F: Opeartion training for BYDOL / BYDOLの操作訓練
u'sというスクールアイドルを結成した私達は，さらなる高みを目指すため，部室にあったDVDで憧れの841プロダクションに所属するアイドル達を見ていた． このアイドル達は今でこそ輝くステージの上で活躍しているが，以前はBYDOLと呼ばれるロボットに乗り込み，隕石の撤去作業をしていたらしい． そこで，トップアイドルになるために，BYDOLの操縦技術が必要であることを知った私達は，急遽BYDOLを入手し，他校のスクールアイドルとBYDOLを用いた模擬戦をすることにした．
この模擬戦では，白の軍と赤の軍に分かれ，BYDOLに積まれている弾により撃ち合いを行う． 各軍のメンバは，それぞれBYDOLに乗り込み，合図が出ると同時に
「1度だけ」
弾を撃つ． 合図が出る時点での全てのBYDOLの座標は決まっており，BYDOL同士はレーダーによって互いの座標を把握できる． 同じ座標にBYDOLが2台以上現れることはない．
BYDOLが移動できるフィールドは2次元平面で表され，非常に広くフィールド全体を囲む壁はないものとして考える． しかし，フィールド内部にいくつかの円形の壁が用意されている． この壁の内側は，コンクリートで塗り固められているため，BYDOLが侵入することはできない． 壁を構成する円は，互いに接したり交差したり内包関係になったりすることはなく，BYDOLがいる座標上に壁は存在しない．
各BYDOLには，合図が出る時点で位置する座標，射程，1度に発射できる弾数，壁で反射する弾を積んでいるか，倒された時に敵軍が得る点数の5つのパラメータが設定されている．
弾は，BYDOLがいる位置から360度どの方向へも発射することができ，一直線状に進む． 発射されてから進んだ弾の距離が射程の値以下である間，かつ他のBYDOLや壁に弾が当たらない間であれば，弾は進み続ける． フィールド上を動く全ての弾は，弾道が交差していても衝突しないものとする．
BYDOLによっては壁で反射する弾を積んでいる場合がある． この場合のBYDOLの弾は全て，1回のみ壁で反射する． ただし，自分のBYDOLから壁の反射した地点までの距離と，反射した地点から相手のBYDOLまでの距離の合計が，射程の値以下でなければ，相手に当たったことにはならない． 壁で反射するときは図1のように，弾が壁に当たった地点に対して接線を引き，この線を基準に入射角
θ
1
と反射角
θ
2
が等しくなるように反射する． 弾道が壁を構成する円に接する場合，そのまままっすぐ弾は進み，壁で反射したことにはならない．
図1:
弾の反射
あるBYDOLは，発射できる弾数の範囲で，1度に複数の弾を撃ち，複数のBYDOLに当てることができる．ただし，同じBYDOLが，全く同じ方向へ向かって弾を2発以上撃つことは許されない．
各BYDOLには，倒された時に敵軍が得る点数が設定されている． この撃ち合いでは，より多くの点数を得た軍が勝者となる． 同じ点数を得た場合は，引き分けとする． BYDOLは1発弾を当てれば倒れるため，同じBYDOLに何発撃ち込もうが，得られる点数は1度きりである． 味方のBYDOLを撃った場合，失格になってしまうため絶対に撃ってはいけない． 自滅することも許されない．
u'sにおける作戦指揮担当であるあなたの仕事は，各軍が最大の点数をとれるように行動したときの点数を求め，どちらの軍が勝つことができるのかを判定することである． これができれば，u'sはトップアイドルへ一歩近づくことができるだろう．
Input
入力は次の形式で表される．
n
m
o
ax
1
ay
1
ap
1
aq
1
ar
1
as
1
...
ax
n
ay
n
ap
n
aq
n
ar
n
as
n
bx
1
by
1
bp
1
bq
1
br
1
bs
1
...
bx
m
by
m
bp
m
bq
m
br
m
bs
m
wx
1
wy
1
wr
1
...
wx
o
wy
o
wr
o
全ての数値は整数で入力される．
n
,
m
(1 ≦
n
,
m
≦ 50) は白の軍と赤の軍のBYDOLの数，
o
(0 ≦
o
≦ 15) は壁の数を表す．
ax
i
,
ay
i
(0 ≦
ax
i
,
ay
i
≦ 100) はi番目の白の軍のBYDOLの座標，
ap
i
(0 ≦
ap
i
≦ 200) は射程，
aq
i
(1 ≦
aq
i
≦ 5) は1度に発射できる弾の数，
ar
i
(0 <=
ar
i
<= 1) は壁で反射する弾を積んでいるかどうか，
as
i
(0≦
as
i
≦ 100) は倒された時に，敵軍が得る点数である．
ar
i
が，0であるときは所持している弾が反射できないこと，1であるときは反射できることを表している． 赤の軍のBYDOLの情報も同様に与えられる．
その後，壁の中心座標(
wx
i
,
wy
i
)と半径
wr
i
が与えられる(0 ≦
wx
i
,
wy
i
≦ 100, 1 ≦
wr
i
≦ 30) ．
Output
白の軍と赤の軍それぞれが，最も点数が得られるように弾を発射したときの点数を空白区切りで1行目に出力せよ． さらに，白の軍が勝つ場合はwin，負ける場合はlose，引き分けの場合はdrawを2行目に出力せよ． 出力には，これら以外の文字があってはならない．
Sample Input 1
2 2 0
0 0 5 1 0 0
1 0 5 1 0 0
0 1 5 1 0 10
1 1 5 1 0 10
Sample Output 1
20 0
win
Sample Input 2
2 3 0
0 0 5 1 0 20
1 0 5 1 0 10
10 10 4 1 0 100
10 0 1 1 0 50
4 0 5 1 0 10
Sample Output 2
10 10
draw
Sample Input 3
1 1 2
0 0 20 1 1 20
10 0 20 1 0 20
5 0 2
5 8 2
Sample Output 3
20 0
win
Sample Input 4
1 1 1
0 0 5 1 0 5
5 0 5 1 0 10
1 1 1
Sample Output 4
10 5
win
Sample Input 5
1 2 5
13 27 19 4 0 30
14 14 34 4 1 9
49 71 21 3 1 31
5 86 18
85 27 3
90 91 1
34 50 10
92 54 15
Sample Output 5
9 30
lose

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
struct MinCostFlow{
    typedef pair<int, int> P; // (最短距離, 頂点の番号)
    static const int INF = 100000000; // infinity

    struct Edge{
        int dst, cap, cost, rev;
        Edge() {}
        Edge(int d, int c, int cs, int r) : 
            dst(d), cap(c), cost(cs), rev(r) {}
    };

    typedef vector<Edge> Node;
    typedef vector<Node> Graph;

    Graph G;

    MinCostFlow(int N) : G(N) {}

    // from から to へ向かう容量cap, 費用costの辺を追加
    void add_edge(int src, int dst, int cap, int cost){
        G[src].push_back(Edge(dst, cap, cost, G[dst].size()));
        G[dst].push_back(Edge(src, 0, -cost, G[src].size() - 1));
    }

    // 頂点sから頂点tへの流量fの最小費用流を求める
    // 流せない場合は-1を返す
    int min_cost_flow(int s, int t, int f){
        int V = G.size();
        vector<int> h(V);
        vector<int> prevv(V), preve(V);
        int res = 0;
        while(f > 0){
            // dijkstraでhを更新する (負の辺がある場合は使えない!)
            priority_queue<P, vector<P>, greater<P>> que;
            vector<int> dist(V, INF);
            dist[s] = 0;
            que.push(P(0, s));

            while(!que.empty()){
                P p = que.top(); que.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];
                    int ndist = dist[v] + e.cost + h[v] - h[e.dst];
                    if(e.cap > 0 && dist[e.dst] > ndist){
                        dist[e.dst] = ndist;
                        prevv[e.dst] = v;
                        preve[e.dst] = i;
                        que.push(P(ndist, e.dst));
                    }
                }
            }

            if(dist[t] == INF){
                // これ以上流せない
                return -1;
            }

            for(int v = 0; v < V; 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;
    }
};

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    if(abs(res) < EPS) res = 0;
    if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p_, double r_) : p(p_), r(r_) {}
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return true; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
const double ZOOM = 5;
const double EDGE = 10;
void draw(Line l){
    REP(i, 2){
        l[i] *= ZOOM;
    }
    fprintf(stderr, "line(%f, %f, %f, %f);\n", l[0].real() + EDGE, l[0].imag(), l[1].real() + EDGE, l[1].imag());
}
void draw(Circle C){
    C.p *= ZOOM;
    C.r *= ZOOM;
    fprintf(stderr, "circle(%f, %f, %f);\n", C.p.real() + EDGE, C.p.imag(), C.r);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    MinCostFlow solver(SINK + 1);
    solver.add_edge(SOURCE, SINK, solver.INF, 0);
    for(int i = 0; i < red.size(); i++){
        solver.add_edge(SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        solver.add_edge(j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }
                for(int k = 0; k < red.size(); k++) if(i != k) {
                    if(intersectSP(s, red[k].p)) ok = false;
                }

                if(ok){
                    arrive = true;
                }
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    if(contains(c, r.p) != OUT) continue;
                    if(contains(c, b.p) != OUT) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 100){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                        double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                        //printf("%f %f\n", th1, th2);
                        if(th1 < th2){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                    double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                    bool ok = true;
                    if(abs(th1 - th2) > EPS){
                        printf("lb: %f\n", lb);
                        printf("r.p: (%f, %f)\n", r.p.real(), r.p.imag());
                        printf("b.p: (%f, %f)\n", b.p.real(), b.p.imag());
                        printf("c.p: (%f, %f)\n", c.p.real(), c.p.imag());
                        printf("c.l: %f\n", c.r);
                        printf("t:   (%f, %f)\n", t.real(), t.imag());
                        printf("th1:%f th2:%f\n", th1, th2);
                        assert(false);
                    }
                    if(intersectSP(s2, r.p)) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) {
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    for(int k2 = 0; k2 < red.size(); k2++) if(i != k2){
                        if(intersectSP(s1, red[k2].p)) ok = false;
                        if(intersectSP(s2, red[k2].p)) ok = false;
                    }
                    if(ok){
                        arrive = true;
                    }
                }
            }
            if(arrive) solver.add_edge(i, j + N, 1, 0);
        }
    }
    int res = solver.min_cost_flow(SOURCE, SINK, solver.INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        srand(time(NULL));
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }

        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }
        /*
        REP(i, 500){
            BYDOL r;
            r.p = Point(rand() % 100, rand() % 100);
            r.len = rand() % 100, r.bull = 5, r.refl = 1, r.score = 100;
            bool ok = true;
            REP(j, O) if(contains(walls[j], r.p) != OUT) ok = false;
            if(!ok) continue;
            if(i % 2 == 0) red.push_back(r);
            else blue.push_back(r);
        }
        */

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 1660
memory_kb: 1404
final_rank: 1

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < V; iter++){
            bool update = false;
            for(int from = 0; from < V; from++){
                if(dist[from] == INF) continue;
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    if(abs(res) < EPS) res = 0;
    if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p_, double r_) : p(p_), r(r_) {}
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return true; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
const double ZOOM = 5;
const double EDGE = 10;
void draw(Line l){
    REP(i, 2){
        l[i] *= ZOOM;
    }
    fprintf(stderr, "line(%f, %f, %f, %f);\n", l[0].real() + EDGE, l[0].imag(), l[1].real() + EDGE, l[1].imag());
}
void draw(Circle C){
    C.p *= ZOOM;
    C.r *= ZOOM;
    fprintf(stderr, "circle(%f, %f, %f);\n", C.p.real() + EDGE, C.p.imag(), C.r);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }
                for(int k = 0; k < red.size(); k++) if(i != k) {
                    if(intersectSP(s, red[k].p)) ok = false;
                }

                if(ok){
                    arrive = true;
                }
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    if(contains(c, r.p) != OUT) continue;
                    if(contains(c, b.p) != OUT) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 100){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                        double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                        //printf("%f %f\n", th1, th2);
                        if(th1 < th2){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                    double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                    bool ok = true;
                    if(abs(th1 - th2) > EPS){
                        printf("lb: %f\n", lb);
                        printf("r.p: (%f, %f)\n", r.p.real(), r.p.imag());
                        printf("b.p: (%f, %f)\n", b.p.real(), b.p.imag());
                        printf("c.p: (%f, %f)\n", c.p.real(), c.p.imag());
                        printf("c.l: %f\n", c.r);
                        printf("t:   (%f, %f)\n", t.real(), t.imag());
                        printf("th1:%f th2:%f\n", th1, th2);
                        assert(false);
                    }
                    if(intersectSP(s2, r.p)) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) {
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    for(int k2 = 0; k2 < red.size(); k2++) if(i != k2){
                        if(intersectSP(s1, red[k2].p)) ok = false;
                        if(intersectSP(s2, red[k2].p)) ok = false;
                    }
                    if(ok){
                        arrive = true;
                    }
                }
            }
            if(arrive) add_edge(G, i, j + N, 1, 0);
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        srand(time(NULL));
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }

        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }
        /*
        REP(i, 500){
            BYDOL r;
            r.p = Point(rand() % 100, rand() % 100);
            r.len = rand() % 100, r.bull = 5, r.refl = 1, r.score = 100;
            bool ok = true;
            REP(j, O) if(contains(walls[j], r.p) != OUT) ok = false;
            if(!ok) continue;
            if(i % 2 == 0) red.push_back(r);
            else blue.push_back(r);
        }
        */

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 1620
memory_kb: 1412
final_rank: 2

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < V; iter++){
            bool update = false;
            for(int from = 0; from < V; from++){
                if(dist[from] == INF) continue;
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    if(abs(res) < EPS) res = 0;
    if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p_, double r_) : p(p_), r(r_) {}
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return true; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
const double ZOOM = 5;
const double EDGE = 10;
void draw(Line l){
    REP(i, 2){
        l[i] *= ZOOM;
    }
    fprintf(stderr, "line(%f, %f, %f, %f);\n", l[0].real() + EDGE, l[0].imag(), l[1].real() + EDGE, l[1].imag());
}
void draw(Circle C){
    C.p *= ZOOM;
    C.r *= ZOOM;
    fprintf(stderr, "circle(%f, %f, %f);\n", C.p.real() + EDGE, C.p.imag(), C.r);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }
                for(int k = 0; k < red.size(); k++) if(i != k) {
                    if(intersectSP(s, red[k].p)) ok = false;
                }

                if(ok){
                    arrive = true;
                }
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    if(contains(c, r.p) != OUT) continue;
                    if(contains(c, b.p) != OUT) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 100){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                        double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                        //printf("%f %f\n", th1, th2);
                        if(th1 < th2){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                    double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                    bool ok = true;
                    if(abs(th1 - th2) > EPS){
                        printf("lb: %f\n", lb);
                        printf("r.p: (%f, %f)\n", r.p.real(), r.p.imag());
                        printf("b.p: (%f, %f)\n", b.p.real(), b.p.imag());
                        printf("c.p: (%f, %f)\n", c.p.real(), c.p.imag());
                        printf("c.l: %f\n", c.r);
                        printf("t:   (%f, %f)\n", t.real(), t.imag());
                        printf("th1:%f th2:%f\n", th1, th2);
                        assert(false);
                    }
                    if(intersectSP(s2, r.p)) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) {
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    for(int k2 = 0; k2 < red.size(); k2++) if(j != i){
                        if(intersectSP(s1, red[k2].p)) ok = false;
                        if(intersectSP(s2, red[k2].p)) ok = false;
                    }
                    if(ok){
                        arrive = true;
                    }
                }
            }
            if(arrive) add_edge(G, i, j + N, 1, 0);
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        srand(time(NULL));
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }

        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }
        /*
        REP(i, 500){
            BYDOL r;
            r.p = Point(rand() % 100, rand() % 100);
            r.len = rand() % 100, r.bull = 5, r.refl = 1, r.score = 100;
            bool ok = true;
            REP(j, O) if(contains(walls[j], r.p) != OUT) ok = false;
            if(!ok) continue;
            if(i % 2 == 0) red.push_back(r);
            else blue.push_back(r);
        }
        */

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.26
time_ms: 1000
memory_kb: 1396
final_rank: 20

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < V; iter++){
            bool update = false;
            for(int from = 0; from < V; from++){
                if(dist[from] == INF) continue;
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    if(abs(res) < EPS) res = 0;
    if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p_, double r_) : p(p_), r(r_) {}
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return true; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
const double ZOOM = 5;
const double EDGE = 10;
void draw(Line l){
    REP(i, 2){
        l[i] *= ZOOM;
    }
    fprintf(stderr, "line(%f, %f, %f, %f);\n", l[0].real() + EDGE, l[0].imag(), l[1].real() + EDGE, l[1].imag());
}
void draw(Circle C){
    C.p *= ZOOM;
    C.r *= ZOOM;
    fprintf(stderr, "circle(%f, %f, %f);\n", C.p.real() + EDGE, C.p.imag(), C.r);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok){
                    arrive = true;
                }
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    if(contains(c, r.p) != OUT) continue;
                    if(contains(c, b.p) != OUT) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 100){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                        double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                        //printf("%f %f\n", th1, th2);
                        if(th1 < th2){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                    double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                    bool ok = true;
                    if(abs(th1 - th2) > EPS){
                        printf("lb: %f\n", lb);
                        printf("r.p: (%f, %f)\n", r.p.real(), r.p.imag());
                        printf("b.p: (%f, %f)\n", b.p.real(), b.p.imag());
                        printf("c.p: (%f, %f)\n", c.p.real(), c.p.imag());
                        printf("c.l: %f\n", c.r);
                        printf("t:   (%f, %f)\n", t.real(), t.imag());
                        printf("th1:%f th2:%f\n", th1, th2);
                        assert(false);
                    }
                    if(intersectSP(s2, r.p)) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) {
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        arrive = true;
                    }
                }
            }
            if(arrive) add_edge(G, i, j + N, 1, 0);
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        srand(time(NULL));
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }

        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }
        /*
        REP(i, 500){
            BYDOL r;
            r.p = Point(rand() % 100, rand() % 100);
            r.len = rand() % 100, r.bull = 5, r.refl = 1, r.score = 100;
            bool ok = true;
            REP(j, O) if(contains(walls[j], r.p) != OUT) ok = false;
            if(!ok) continue;
            if(i % 2 == 0) red.push_back(r);
            else blue.push_back(r);
        }
        */

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.4
time_ms: 820
memory_kb: 1404
final_rank: 11

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < V; iter++){
            bool update = false;
            for(int from = 0; from < V; from++){
                if(dist[from] == INF) continue;
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p_, double r_) : p(p_), r(r_) {}
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return true; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
const double ZOOM = 5;
const double EDGE = 10;
void draw(Line l){
    REP(i, 2){
        l[i] *= ZOOM;
    }
    fprintf(stderr, "line(%f, %f, %f, %f);\n", l[0].real() + EDGE, l[0].imag(), l[1].real() + EDGE, l[1].imag());
}
void draw(Circle C){
    C.p *= ZOOM;
    C.r *= ZOOM;
    fprintf(stderr, "circle(%f, %f, %f);\n", C.p.real() + EDGE, C.p.imag(), C.r);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok){
                    arrive = true;
                }
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 100){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                        double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                        //printf("%f %f\n", th1, th2);
                        if(th1 < th2){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                    double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                    //cout << lb << " " << c.p << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", th1, th2);
                    bool ok = true;
                    //if(abs(th1 - th2) > EPS) ok = false; // true???
                    if(intersectSP(s2, r.p)) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) {
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        arrive = true;
                    }
                }
            }
            if(arrive) add_edge(G, i, j + N, 1, 0);
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.4
time_ms: 800
memory_kb: 1400
final_rank: 10

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < V; iter++){
            bool update = false;
            for(int from = 0; from < V; from++){
                if(dist[from] == INF) continue;
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return true; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) arrive = true;
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                        double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                        //printf("%f %f\n", th1, th2);
                        if(th1 < th2){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                    double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                    //cout << lb << " " << c.p << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", th1, th2);
                    bool ok = true;
                    if(abs(th1 - th2) > EPS) ok = false; // true???
                    if(intersectSP(s2, r.p)) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) {
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        arrive = true;
                    }
                }
            }
            if(arrive) add_edge(G, i, j + N, 1, 0);
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.4
time_ms: 640
memory_kb: 1404
final_rank: 9

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < V; iter++){
            bool update = false;
            for(int from = 0; from < V; from++){
                if(dist[from] == INF) continue;
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return true; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) arrive = true;
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                        double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                        //printf("%f %f\n", th1, th2);
                        if(th1 < th2){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                    double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                    //cout << lb << " " << c.p << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", th1, th2);
                    bool ok = true;
                    if(abs(th1 - th2) > EPS) ok = false; // true???
                    if(intersectSP(s2, r.p)) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        arrive = true;
                    }
                }
            }
            if(arrive) add_edge(G, i, j + N, 1, 0);
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.4
time_ms: 630
memory_kb: 1400
final_rank: 8

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < V; iter++){
            bool update = false;
            for(int from = 0; from < V; from++){
                if(dist[from] == INF) continue;
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return true; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) arrive = true;
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                        double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                        //printf("%f %f\n", th1, th2);
                        if(th1 < th2){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                    double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                    //cout << lb << " " << c.p << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", th1, th2);
                    assert(abs(th1 - th2) < 1e-4);
                    bool ok = true;
                    if(intersectSP(s2, r.p)) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        arrive = true;
                    }
                }
            }
            if(arrive) add_edge(G, i, j + N, 1, 0);
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.26
time_ms: 10
memory_kb: 1348
final_rank: 14

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < V; iter++){
            bool update = false;
            for(int from = 0; from < V; from++){
                if(dist[from] == INF) continue;
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return true; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) arrive = true;
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                        double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                        //printf("%f %f\n", th1, th2);
                        if(th1 < th2){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                    double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                    //cout << lb << " " << c.p << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", th1, th2);
                    //assert(abs(th1 - th2) < EPS);
                    bool ok = true;
                    if(intersectSP(s2, r.p)) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        arrive = true;
                    }
                }
            }
            if(arrive) add_edge(G, i, j + N, 1, 0);
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.4
time_ms: 620
memory_kb: 1396
final_rank: 6

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < V; iter++){
            bool update = false;
            for(int from = 0; from < V; from++){
                if(dist[from] == INF) continue;
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return true; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) arrive = true;
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                        double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                        if(th1 < th2){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    double th1 = (ccw(c.p, r.p, b.p) > 0 ? angle(r.p - t, t - c.p) : angle(t - c.p, r.p - t));
                    double th2 = (ccw(c.p, r.p, b.p) > 0 ? angle(t - c.p, b.p - t) : angle(b.p - t, t - c.p));
                    //cout << lb << " " << c.p << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", th1, th2);
                    assert(abs(th1 - th2) < EPS);
                    bool ok = true;
                    if(intersectSP(s2, r.p)) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        arrive = true;
                    }
                }
            }
            if(arrive) add_edge(G, i, j + N, 1, 0);
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.26
time_ms: 10
memory_kb: 1348
final_rank: 14

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < V; iter++){
            bool update = false;
            for(int from = 0; from < V; from++){
                if(dist[from] == INF) continue;
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    //if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return false; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) arrive = true;
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        if(abs(angle(r.p - t, t - c.p)) < abs(angle(t - c.p, b.p - t))){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    //cout << lb << " " << c.p << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", abs(angle(r.p - t, t - c.p)), abs(angle(t - c.p, b.p - t)));
                    assert(abs(angle(r.p - t, t - c.p) - angle(t - c.p, b.p - t)) < EPS);
                    bool ok = true;
                    if(intersectSP(s2, r.p)) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        assert(abs(angle(r.p - t, t - c.p)) > EPS);
                        assert(abs(angle(t - c.p, b.p - t)) > EPS);
                        arrive = true;
                    }
                }
            }
            if(arrive) add_edge(G, i, j + N, 1, 0);
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.4
time_ms: 550
memory_kb: 1400
final_rank: 7

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> h(V);
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < G.size(); iter++){
            bool update = false;
            for(int from = 0; from < G.size(); from++){
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[from] != INF && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    //if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p, double r) : p(p), r(r) { }
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return false; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) arrive = true;
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        if(abs(angle(r.p - t, t - c.p)) < abs(angle(t - c.p, b.p - t))){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    //cout << lb << " " << c.p << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", abs(angle(r.p - t, t - c.p)), abs(angle(t - c.p, b.p - t)));
                    assert(abs(angle(r.p - t, t - c.p)) > -EPS);
                    assert(abs(angle(t - c.p, b.p - t)) > -EPS);
                    assert(abs(angle(r.p - t, t - c.p) - angle(t - c.p, b.p - t)) < EPS);
                    bool ok = true;
                    if(intersectSP(s2, r.p)) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        arrive = true;
                    }
                }
            }
            if(arrive) add_edge(G, i, j + N, 1, 0);
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.4
time_ms: 540
memory_kb: 1396
final_rank: 5

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> h(V);
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < G.size(); iter++){
            bool update = false;
            for(int from = 0; from < G.size(); from++){
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[from] != INF && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    //if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p, double r) : p(p), r(r) { }
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return false; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) arrive = true;
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        if(abs(angle(r.p - t, t - c.p)) < abs(angle(t- c.p, b.p - t))){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    //cout << lb << " " << c.p << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", abs(angle(r.p - t, t - c.p)), abs(angle(t - c.p, b.p - t)));
                    assert(abs(angle(r.p - t, t - c.p)) > -EPS);
                    assert(abs(angle(t - c.p, b.p - t)) > -EPS);
                    assert(abs(angle(r.p - t, t - c.p) - angle(t - c.p, b.p - t)) < EPS);
                    bool ok = true;
                    if(abs(lb) < EPS || abs(lb - 1) < EPS) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        arrive = true;
                    }
                }
            }
            if(arrive) add_edge(G, i, j + N, 1, 0);
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.4
time_ms: 530
memory_kb: 1396
final_rank: 4

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> h(V);
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < G.size(); iter++){
            bool update = false;
            for(int from = 0; from < G.size(); from++){
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[from] != INF && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-6;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    //if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p, double r) : p(p), r(r) { }
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return false; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            bool arrive = false;
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) arrive = true;
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        if(abs(angle(r.p - t, t - c.p)) < abs(angle(t- c.p, b.p - t))){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    //cout << lb << " " << c.p << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", abs(angle(r.p - t, t - c.p)), abs(angle(t - c.p, b.p - t)));
                    assert(abs(angle(r.p - t, t - c.p)) > -EPS);
                    assert(abs(angle(t - c.p, b.p - t)) > -EPS);
                    assert(abs(angle(r.p - t, t - c.p) - angle(t - c.p, b.p - t)) < EPS);
                    bool ok = true;
                    if(abs(lb) < EPS || abs(lb - 1) < EPS) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        arrive = true;
                    }
                }
            }
            if(arrive) add_edge(G, i, j + N, 1, 0);
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.4
time_ms: 540
memory_kb: 1392
final_rank: 3

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> h(V);
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < G.size(); iter++){
            bool update = false;
            for(int from = 0; from < G.size(); from++){
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[from] != INF && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-6;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    //if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p, double r) : p(p), r(r) { }
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return false; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) add_edge(G, i, j + N, 1, 0);
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        if(abs(angle(r.p - t, t - c.p)) < abs(angle(t- c.p, b.p - t))){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    //cout << lb << " " << c.p << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", abs(angle(r.p - t, t - c.p)), abs(angle(t - c.p, b.p - t)));
                    assert(abs(angle(r.p - t, t - c.p)) > -EPS);
                    assert(abs(angle(t - c.p, b.p - t)) > -EPS);
                    assert(abs(angle(r.p - t, t - c.p) - angle(t - c.p, b.p - t)) < EPS);
                    bool ok = true;
                    if(abs(lb) < EPS || abs(lb - 1) < EPS) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        add_edge(G, i, j + N, 1, 0);
                    }
                }
            }
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.4
time_ms: 550
memory_kb: 1416
final_rank: 13

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> h(V);
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < G.size(); iter++){
            bool update = false;
            for(int from = 0; from < G.size(); from++){
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[from] != INF && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-6;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    //if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p, double r) : p(p), r(r) { }
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return false; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) add_edge(G, i, j + N, 1, 0);
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        if(abs(angle(r.p - t, t - c.p)) < abs(angle(t- c.p, b.p - t))){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    //cout << lb << " " << c.p << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", abs(angle(r.p - t, t - c.p)), abs(angle(t - c.p, b.p - t)));
                    assert(abs(angle(r.p - t, t - c.p)) > -EPS);
                    assert(abs(angle(t - c.p, b.p - t)) > -EPS);
                    assert(abs(angle(r.p - t, t - c.p) - angle(t - c.p, b.p - t)) < EPS);
                    bool ok = true;
                    if(abs(angle(r.p - t, t - c.p)) < EPS) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        assert(abs(lb - 0) > EPS);
                        assert(abs(lb - 1) > EPS);
                        add_edge(G, i, j + N, 1, 0);
                    }
                }
            }
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.4
time_ms: 540
memory_kb: 1416
final_rank: 12

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> h(V);
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < G.size(); iter++){
            bool update = false;
            for(int from = 0; from < G.size(); from++){
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[from] != INF && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-6;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    double res = arg(conj(a) * b);
    //if(res < 0) res = res + 2 * M_PI;
    return res;
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p, double r) : p(p), r(r) { }
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return false; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) add_edge(G, i, j + N, 1, 0);
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        if(abs(angle(r.p - t, t - c.p)) < abs(angle(t- c.p, b.p - t))){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    //cout << lb << " " << c.p << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", abs(angle(r.p - t, t - c.p)), abs(angle(t - c.p, b.p - t)));
                    assert(abs(angle(r.p - t, t - c.p)) > -EPS);
                    assert(abs(angle(t - c.p, b.p - t)) > -EPS);
                    assert(abs(angle(r.p - t, t - c.p) - angle(t - c.p, b.p - t)) < EPS);
                    bool ok = true;
                    if(angle(r.p - t, t - c.p) < EPS) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        assert(abs(lb - 0) > EPS);
                        assert(abs(lb - 1) > EPS);
                        add_edge(G, i, j + N, 1, 0);
                    }
                }
            }
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.26
time_ms: 540
memory_kb: 1404
final_rank: 19

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> h(V);
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < G.size(); iter++){
            bool update = false;
            for(int from = 0; from < G.size(); from++){
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[from] != INF && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-6;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    return arg(conj(a) * b);
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p, double r) : p(p), r(r) { }
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return false; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) add_edge(G, i, j + N, 1, 0);
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        if(angle(r.p - t, t - c.p) < angle(t- c.p, b.p - t)){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    //cout << lb << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", angle(r.p - t, t - c.p), angle(t - c.p, b.p - t));
                    bool ok = true;
                    if(angle(r.p - t, t - c.p) < EPS) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        assert(abs(lb - 0) > EPS);
                        assert(abs(lb - 1) > EPS);
                        add_edge(G, i, j + N, 1, 0);
                    }
                }
            }
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.26
time_ms: 520
memory_kb: 1400
final_rank: 16

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> h(V);
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < G.size(); iter++){
            bool update = false;
            for(int from = 0; from < G.size(); from++){
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[from] != INF && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    return arg(conj(a) * b);
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p, double r) : p(p), r(r) { }
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return false; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) add_edge(G, i, j + N, 1, 0);
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        if(angle(r.p - t, t - c.p) < angle(t- c.p, b.p - t)){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    //cout << lb << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", angle(r.p - t, t - c.p), angle(t - c.p, b.p - t));
                    bool ok = true;
                    if(angle(r.p - t, t - c.p) < EPS) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok){
                        assert(abs(lb - 0) > EPS);
                        assert(abs(lb - 1) > EPS);
                        add_edge(G, i, j + N, 1, 0);
                    }
                }
            }
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.26
time_ms: 520
memory_kb: 1400
final_rank: 16

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;

// --- min_cost_flow --- 
typedef pair<int, int> P; // (最短距離, 頂点の番号)
const int INF = 100000000; // infinity

struct Edge{
    int to, cap, cost, rev;
    Edge() {}
    Edge(int t, int c, int cs, int r) : 
        to(t), cap(c), cost(cs), rev(r) {}
};

typedef vector<Edge> Node;
typedef vector<Node> Graph;

// from から to へ向かう容量cap, 費用costの辺を追加
void add_edge(Graph& G, int from, int to, int cap, int cost){
    G[from].push_back(Edge(to, cap, cost, G[to].size()));
    G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1));
}

int min_cost_flow(Graph G, int s, int t, int f){
    int V = G.size();
    vector<int> h(V);
    vector<int> prevv(V), preve(V);
    int res = 0;
    //REP(from, G.size()) REP(i, G[from].size()) printf("%d -> %d %d %d\n", from, G[from][i].to, G[from][i].cap, G[from][i].cost);
    while(f > 0){
        vector<int> dist(V, INF);
        dist[s] = 0;

        for(int iter = 0; iter < G.size(); iter++){
            bool update = false;
            for(int from = 0; from < G.size(); from++){
                for(int i = 0; i < G[from].size(); i++){
                    const Edge& e = G[from][i];
                    if(e.cap > 0 && dist[from] != INF && dist[e.to] > dist[from] + e.cost){
                        dist[e.to] = dist[from] + e.cost;
                        prevv[e.to] = from;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
            if(!update) break;
            assert(iter + 1 != G.size());
        }

        if(dist[t] == INF){
            // これ以上流せない
            assert(false);
        }

        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;
}
// --- min_cost_flow ---

// --- geometory --- 
const double EPS = 1e-8;
int sign(double a){
    if(a > EPS) return +1;
    if(a < -EPS) return -1;
    return 0;
}
typedef complex<double> Point;
double angle(Point a, Point b){
    return arg(conj(a) * b);
}
double dot(Point a, Point b){
    return real(conj(a) * b);
}
double cross(Point a, Point b){
    return imag(conj(a) * b);
}
int ccw(Point a, Point b, Point c) {
    b -= a; c -= a;
    double len = abs(b) * abs(c); // 速さが気になるときは1にする
    if (cross(b, c) > +len * EPS)   return +1; // 反時計回り
    if (cross(b, c) < -len * EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
struct Line : public vector<Point> {
    Line(const Point& a, const Point& b) {
        push_back(a); push_back(b);
    }
    Point vector() const {
        return back() - front();
    }
};
Point projection(Line l, Point p){
    double t = dot(p - l[0], l.vector()) / norm(l.vector());
    return l[0] + t * l.vector();
}
bool intersectSP(Line s, Point p) {
    return ccw(s[0], s[1], p) == 0;
}
double distanceSP(Line s, Point p){
    Point r = projection(s, p);
    if(intersectSP(s, r)) return abs(r - p); // 垂線が線分に交わるとき
    return min(abs(s[0] - p), abs(s[1] - p));
}
struct Circle {
    Point p;
    double r;
    Circle() {}
    Circle(Point p, double r) : p(p), r(r) { }
};
enum{ OUT, ON, IN };
int contains(const Circle& C, const Point& p){
    double d = abs(C.p - p);
    if(sign(d - C.r) > 0) return OUT;
    if(sign(d - C.r) == 0) return ON;
    return IN;
}

bool intersectCS(const Circle& C, const Line& l){
    int b[2];
    for(int i = 0; i < 2; i++){
        b[i] = contains(C, l[i]);
    }
    if(b[0] > b[1]) swap(b[0], b[1]);

    // (OUT, OUT) (OUT, ON) (OUT, IN) (ON, ON) (ON, IN) (IN, IN) の6通り
    if(b[0] == OUT && b[1] == IN) return true;
    if(b[0] == IN && b[1] == IN) return false;
    if(b[0] == ON) return false; // (接するとき) 
    double d = distanceSP(l, C.p);
    if(sign(d - C.r) < 0) return true;
    if(sign(d - C.r) == 0) return false; // (接するとき)
    if(sign(d - C.r) > 0) return false;
    assert(false);
}
// --- geometory ---

struct BYDOL{
    Point p;
    double len;
    int bull;
    int refl;
    int score;
};
int solve(const vector<BYDOL>& red,  const vector<BYDOL>& blue, const vector<Circle>& walls){
    int N = red.size();
    int M = blue.size();
    const int SOURCE = N + M;
    const int SINK = SOURCE + 1;
    Graph G(SINK + 1);
    add_edge(G, SOURCE, SINK, INF, 0);
    for(int i = 0; i < red.size(); i++){
        add_edge(G, SOURCE, i, red[i].bull, 0);
    }
    for(int j = 0; j < blue.size(); j++){
        add_edge(G, j + N, SINK, 1, -blue[j].score);
    }
    for(int i = 0; i < red.size(); i++){
        for(int j = 0; j < blue.size(); j++){
            const BYDOL& r = red[i];
            const BYDOL& b = blue[j];
            // one-line
            Line s(r.p, b.p);
            {
                bool ok = true;
                if(abs(s.vector()) > r.len + EPS) ok = false;
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) ok = false;
                }
                for(int k = 0; k < blue.size(); k++) if(j != k) {
                    if(intersectSP(s, blue[k].p)) ok = false;
                }

                if(ok) add_edge(G, i, j + N, 1, 0);
            }
            // two-line
            if(r.refl){
                for(int k = 0; k < walls.size(); k++){
                    const Circle& c = walls[k];
                    if(intersectCS(c, s)) continue;
                    double lb = 0, ub = 1;
                    REP(iter, 64){
                        double mid = (lb + ub) / 2;
                        Point p = r.p + (b.p - r.p) * mid;
                        Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                        if(angle(r.p - t, t - c.p) < angle(t- c.p, b.p - t)){
                            lb = mid;
                        }else{
                            ub = mid;
                        }
                    }
                    Point p = r.p + (b.p - r.p) * lb;
                    Point t = c.p + (p - c.p) / abs(p - c.p) * c.r;
                    Line s1(r.p, t);
                    Line s2(t, b.p);
                    //cout << lb << " ";
                    //cout << r.p << " -> " << t << " -> " << b.p << endl;
                    //printf("%f %f\n", angle(r.p - t, t - c.p), angle(t - c.p, b.p - t));
                    bool ok = true;
                    if(angle(r.p - t, t - c.p) < EPS) ok = false;
                    if(abs(s1.vector()) + abs(s2.vector()) > r.len + EPS) ok = false;
                    for(int k2 = 0; k2 < walls.size(); k2++) if(k != k2){
                        const Circle& c2 = walls[k2];
                        if(intersectCS(c2, s1)) ok = false;
                        if(intersectCS(c2, s2)) ok = false;
                    }
                    for(int k2 = 0; k2 < blue.size(); k2++) if(j != k2){
                        if(intersectSP(s1, blue[k2].p)) ok = false;
                        if(intersectSP(s2, blue[k2].p)) ok = false;
                    }
                    if(ok) add_edge(G, i, j + N, 1, 0);
                }
            }
        }
    }
    int res = min_cost_flow(G, SOURCE, SINK, INF);
    return -res;
}
int main(){
    int N, M, O;
    while(cin >> N >> M >> O){
        vector<BYDOL> red(N), blue(M);
        REP(i, N) {
            BYDOL& r = red[i];
            double x, y;
            cin >> x >> y;
            r.p = Point(x, y);
            cin >> r.len >> r.bull >> r.refl >> r.score;
        }
        REP(i, M) {
            BYDOL& b = blue[i];
            double x, y;
            cin >> x >> y;
            b.p = Point(x, y);
            cin >> b.len >> b.bull >> b.refl >> b.score;
        }
        vector<Circle> walls(O);
        REP(i, O){
            double x, y;
            cin >> x >> y;
            walls[i].p = Point(x, y);
            cin >> walls[i].r;
        }

        int rpoint = solve(red, blue, walls);
        int bpoint = solve(blue, red, walls);
        string result = (rpoint > bpoint ? "win" : rpoint < bpoint ? "lose" : "draw");
        cout << rpoint << " " << bpoint << endl;
        cout << result << endl;
    }
    return 0;
}
accuracy: 0.26
time_ms: 510
memory_kb: 1404
final_rank: 18