Problem:
サッカー (Soccer)

問題

JOI 国ではサッカーが人気であり，JOI リーグというリーグ戦が毎週行われている．

JOI リーグには N 個のチームが所属していて，1 から N までの番号がつけられている．すべての組み合わせの試合がちょうど一度ずつ行われる．つまり， N × (N - 1) / 2 試合が行われる．各試合の勝敗はそれぞれのチームの得点で決まる．勝ったチームの勝ち点は 3 点であり，負けたチームの勝ち点は 0 点である．引き分けの場合，両チームの勝ち点は 1 点である．順位は各チームの獲得した勝ち点の合計で決定し，得失点差は考えない．勝ち点の合計が等しいチームの順位は上位に揃える．

例として， 4 チームでのリーグ戦を考える．4 × (4 - 1) / 2 = 6 試合が行われる．それらの結果が以下の表のようになったとする．ハイフンの左側はその横のチームの得点であり，右側はその縦のチームの得点である．

  チーム 1  

  チーム 2  

  チーム 3  

  チーム 4  

  勝ち数  

  負け数  

  引き分け数  

  勝ち点  

  チーム 1  

---

0 - 1

2 - 1

2 - 2

1

1

1

4

  チーム 2  

1 - 0

---

1 - 1

3 - 0

2

0

1

7

  チーム 3  

1 - 2

1 - 1

---

1 - 3

0

2

1

1

  チーム 4  

2 - 2

0 - 3

3 - 1

---

1

1

1

4

このとき，勝ち点の最も多いチーム 2 が 1 位である．

その次に勝ち点が多いチームはチーム 1 とチーム 4 であり，これらのチームの順位は共に 2 位である．

そして勝ち点が最も少ないチーム 3 が 4 位である．

全ての試合の結果が与えられたとき，各チームの順位を求めるプログラムを作成せよ．

入力

入力ファイルの 1 行目にはチームの個数 N (2 ≦ N ≦ 100) が書かれている．続く N × (N - 1) / 2 行には各試合の結果が書かれている．i + 1 行目 (1 ≦ i ≦ N × (N - 1) / 2) には整数 Ai，Bi，Ci，Di (1 ≦ Ai ≦ N，1 ≦ Bi ≦ N，0 ≦ Ci ≦ 100，0 ≦ Di ≦ 100) が空白を区切りとして書かれており，チーム Ai とチーム Bi が対戦し，チーム Ai の得点が Ci 点，チーム Bi の得点が Di 点であったことを表す．全ての i について Ai ≠ Bi であり，同じ組み合わせの対戦が書かれていることはない．

出力

出力は N 行からなる．各行は 1 つの整数からなり， i 行目 (1 ≦ i ≦ N) の整数はチーム i の順位を表す．

入出力例

入力例 1

4
1 2 0 1
1 3 2 1
1 4 2 2
2 3 1 1
2 4 3 0
3 4 1 3

出力例 1

2
1
4
2

入出力例 1 は問題文中の例に対応している．

入力例 2

5
1 2 1 1
3 4 3 1
5 1 1 2
2 3 0 0
4 5 2 3
1 3 0 2
5 2 2 2
4 1 4 5
3 5 4 0
2 4 0 1

出力例 2

2
4
1
4
3

入出力例 2 における結果は以下の通りである．

  勝ち数  

  負け数  

  引き分け数  

  勝ち点  

  チーム 1  

2

1

1

7

  チーム 2  

0

1

3

3

  チーム 3  

3

0

1

10

  チーム 4  

1

3

0

3

  チーム 5  

1

2

1

4

問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in JAVA (judge verdict: Accepted)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.TreeSet;

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		final int N = sc.nextInt();
		
		int[] points = new int[N];
		
		for(int i = 0; i < ((N*(N-1))/2); i++){
			final int A = sc.nextInt() - 1;
			final int B = sc.nextInt() - 1;
			final int C = sc.nextInt();
			final int D = sc.nextInt();
			
			if(C > D){
				points[A] += 3;
			}else if(C < D){
				points[B] += 3;
			}else{
				points[A] += 1;
				points[B] += 1;
			}
		}
		
		TreeSet<Integer> tree = new TreeSet<Integer>();
		for(int i : points){
			tree.add(i);
		}
		
		ArrayList<Integer> list = new ArrayList<Integer>(tree);
		
		
		int[] dup = new int[list.size()];
		for(int i = 0; i < N; i++){
			dup[Collections.binarySearch(list, points[i])]++;
		}
		
		for(int i = 0; i < dup.length; i++){
			dup[i]--;
		}
		//System.out.println(Arrays.toString(dup));
		for(int i = dup.length - 1; i > 0; i--){
			dup[i-1] += dup[i];
		}
		
		dup[dup.length - 1] = 0;
		for(int i = 0; i < dup.length - 1 ; i++){
			dup[i] = dup[i+1];
		}
		
		//System.out.println(Arrays.toString(dup));
		
		for(int i = 0; i < N; i++){
			System.out.println((list.size() - Collections.binarySearch(list, points[i])) + dup[Collections.binarySearch(list, points[i])]);
		}
	}

}