結果
問題 | No.2780 The Bottle Imp |
ユーザー | ks2m |
提出日時 | 2024-06-07 22:10:26 |
言語 | Java21 (openjdk 21) |
結果 |
WA
(最新)
AC
(最初)
|
実行時間 | - |
コード長 | 7,047 bytes |
コンパイル時間 | 2,520 ms |
コンパイル使用メモリ | 97,144 KB |
実行使用メモリ | 99,240 KB |
最終ジャッジ日時 | 2024-06-08 10:30:50 |
合計ジャッジ時間 | 14,504 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 45 ms
36,976 KB |
testcase_01 | AC | 44 ms
37,060 KB |
testcase_02 | AC | 45 ms
36,756 KB |
testcase_03 | AC | 44 ms
37,112 KB |
testcase_04 | AC | 44 ms
36,952 KB |
testcase_05 | AC | 47 ms
37,008 KB |
testcase_06 | AC | 47 ms
37,228 KB |
testcase_07 | AC | 287 ms
55,972 KB |
testcase_08 | AC | 293 ms
55,400 KB |
testcase_09 | AC | 285 ms
55,416 KB |
testcase_10 | AC | 290 ms
55,072 KB |
testcase_11 | AC | 287 ms
55,284 KB |
testcase_12 | AC | 466 ms
67,236 KB |
testcase_13 | AC | 473 ms
67,412 KB |
testcase_14 | AC | 224 ms
49,944 KB |
testcase_15 | AC | 219 ms
49,752 KB |
testcase_16 | AC | 215 ms
49,928 KB |
testcase_17 | AC | 220 ms
49,968 KB |
testcase_18 | AC | 220 ms
49,640 KB |
testcase_19 | AC | 221 ms
50,404 KB |
testcase_20 | AC | 230 ms
48,152 KB |
testcase_21 | AC | 229 ms
48,456 KB |
testcase_22 | AC | 200 ms
46,888 KB |
testcase_23 | AC | 229 ms
50,824 KB |
testcase_24 | AC | 269 ms
54,344 KB |
testcase_25 | AC | 370 ms
61,468 KB |
testcase_26 | AC | 258 ms
53,384 KB |
testcase_27 | AC | 291 ms
53,536 KB |
testcase_28 | AC | 290 ms
52,752 KB |
testcase_29 | AC | 250 ms
56,560 KB |
testcase_30 | AC | 235 ms
54,832 KB |
testcase_31 | AC | 342 ms
55,564 KB |
testcase_32 | AC | 188 ms
45,556 KB |
testcase_33 | AC | 411 ms
77,904 KB |
testcase_34 | AC | 511 ms
99,240 KB |
testcase_35 | AC | 175 ms
46,452 KB |
testcase_36 | AC | 46 ms
36,608 KB |
testcase_37 | AC | 46 ms
37,060 KB |
testcase_38 | AC | 179 ms
46,292 KB |
testcase_39 | AC | 351 ms
64,576 KB |
testcase_40 | AC | 354 ms
64,492 KB |
testcase_41 | AC | 378 ms
64,764 KB |
testcase_42 | WA | - |
testcase_43 | AC | 44 ms
36,628 KB |
ソースコード
import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Deque; import java.util.HashSet; import java.util.List; import java.util.Set; public class Main { static List<Set<Integer>> list; public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine()); int[] m = new int[n]; int[][] a = new int[n][]; for (int i = 0; i < n; i++) { String[] sa = br.readLine().split(" "); m[i] = Integer.parseInt(sa[0]); a[i] = new int[m[i]]; for (int j = 0; j < m[i]; j++) { a[i][j] = Integer.parseInt(sa[j + 1]) - 1; } } br.close(); SCC scc = new SCC(n); for (int i = 0; i < n; i++) { for (int j = 0; j < m[i]; j++) { scc.addEdge(i, a[i][j]); } } int[][] g = scc.scc(); DSU uf = new DSU(n); for (int i = 0; i < g.length; i++) { for (int j = 1; j < g[i].length; j++) { uf.merge(g[i][0], g[i][j]); } } list = new ArrayList<>(n); for (int i = 0; i < n; i++) { list.add(new HashSet<>()); } for (int i = 0; i < n; i++) { for (int j = 0; j < m[i]; j++) { if (!uf.same(i, a[i][j])) { list.get(uf.leader(i)).add(uf.leader(a[i][j])); } } } boolean[] vis = new boolean[n]; boolean res = dfs(uf.leader(0), vis); if (!res) { System.out.println("No"); return; } for (int i = 0; i < n; i++) { if (!vis[uf.leader(i)]) { System.out.println("No"); return; } } System.out.println("Yes"); } static boolean dfs(int x, boolean[] vis) { vis[x] = true; Set<Integer> nexts = list.get(x); if (nexts.size() > 1) { return false; } if (nexts.isEmpty()) { return true; } return dfs(nexts.iterator().next(), vis); } } class SCC { /** gid[i]:頂点iが何番目の強連結成分に属しているか */ int[] gid; private final int n; private List<Edge> edges; private int nowOrd, groupNum; private int[] start, low, ord; private Edge[] elist; private Deque<Integer> visited; private class Edge { final int from, to; public Edge(int from, int to) { this.from = from; this.to = to; } } /** * n頂点0辺のグラフを作る。<br> * O(n) * * @param n 頂点数 */ public SCC(int n) { this.n = n; edges = new ArrayList<>(); } /** * fromからtoへ有向辺を追加する。<br> * ならしO(1) * * @param from 有向辺の始点(0≦from<n) * @param to 有向辺の終点(0≦to<n) */ void addEdge(int from, int to) { assert 0 <= from && from < n : "from=" + from; assert 0 <= to && to < n : "to=" + to; edges.add(new Edge(from, to)); } /** * <pre> * 強連結成分分解 * 辺の本数をmとして、O(n + m) * * ・全ての頂点がちょうど1つずつ、内側の配列のどれかに含まれる。 * ・内側の配列(1つの強連結成分)内での頂点の順序は未定義。 * ・外側の配列はトポロジカルソートされている。 * </pre> * * @return 強連結成分ごとの頂点の配列 */ int[][] scc() { start = new int[n + 1]; for (Edge e : edges) { start[e.from + 1]++; } for (int i = 1; i <= n; i++) { start[i] += start[i - 1]; } elist = new Edge[edges.size()]; int[] counter = Arrays.copyOf(start, n + 1); for (Edge e : edges) { elist[counter[e.from]++] = e; } nowOrd = 0; groupNum = 0; visited = new ArrayDeque<>(); low = new int[n]; ord = new int[n]; gid = new int[n]; Arrays.fill(ord, -1); for (int i = 0; i < n; i++) { if (ord[i] == -1) { dfs(i); } } for (int i = 0; i < n; i++) { gid[i] = groupNum - 1 - gid[i]; } int[] counts = new int[groupNum]; for (int x : gid) { counts[x]++; } int[][] groups = new int[groupNum][]; for (int i = 0; i < groupNum; i++) { groups[i] = new int[counts[i]]; } for (int i = 0; i < n; i++) { int idx = gid[i]; groups[idx][--counts[idx]] = i; } return groups; } private void dfs(int v) { low[v] = ord[v] = nowOrd++; visited.add(v); for (int i = start[v]; i < start[v + 1]; i++) { int to = elist[i].to; if (ord[to] == -1) { dfs(to); low[v] = Math.min(low[v], low[to]); } else { low[v] = Math.min(low[v], ord[to]); } } if (low[v] == ord[v]) { while (true) { int u = visited.pollLast(); ord[u] = n; gid[u] = groupNum; if (u == v) { break; } } groupNum++; } } } class DSU { private int n; private int[] parentOrSize; private int num; /** * n頂点0辺の無向グラフを作る。<br> * O(n) * * @param n 頂点数 */ public DSU(int n) { this.n = n; this.parentOrSize = new int[n]; Arrays.fill(parentOrSize, -1); num = n; } /** * 辺(a, b)を足す。<br> * ならしO(α(n)) * * @param a 頂点番号(0≦a<n) * @param b 頂点番号(0≦b<n) * @return 代表元 */ int merge(int a, int b) { assert 0 <= a && a < n : "a=" + a; assert 0 <= b && b < n : "b=" + b; int x = leader(a); int y = leader(b); if (x == y) { return x; } if (-parentOrSize[x] < -parentOrSize[y]) { int tmp = x; x = y; y = tmp; } parentOrSize[x] += parentOrSize[y]; parentOrSize[y] = x; num--; return x; } /** * 頂点a, bが連結かどうか。<br> * ならしO(α(n)) * * @param a 頂点番号(0≦a<n) * @param b 頂点番号(0≦b<n) * @return true:連結 false:非連結 */ boolean same(int a, int b) { assert 0 <= a && a < n : "a=" + a; assert 0 <= b && b < n : "b=" + b; return leader(a) == leader(b); } /** * 頂点aの属する連結成分の代表元を返す。<br> * ならしO(α(n)) * * @param a 頂点番号(0≦a<n) * @return 代表元 */ int leader(int a) { assert 0 <= a && a < n : "a=" + a; if (parentOrSize[a] < 0) { return a; } else { return parentOrSize[a] = leader(parentOrSize[a]); } } /** * 頂点aの属する連結成分の要素数を返す。<br> * ならしO(α(n)) * * @param a 頂点番号(0≦a<n) * @return 要素数 */ int size(int a) { assert 0 <= a && a < n : "a=" + a; return -parentOrSize[leader(a)]; } /** * 連結成分の数を返す。<br> * O(1) * * @return 連結成分数 */ int num() { return num; } /** * グラフを連結成分に分けた情報を返す。<br> * O(n) * * @return 「1つの連結成分の頂点番号のリスト」のリスト */ List<List<Integer>> groups() { int[] leaderBuf = new int[n]; int[] groupSize = new int[n]; for (int i = 0; i < n; i++) { leaderBuf[i] = leader(i); groupSize[leaderBuf[i]]++; } List<List<Integer>> result = new ArrayList<>(n); for (int i = 0; i < n; i++) { result.add(new ArrayList<>(groupSize[i])); } for (int i = 0; i < n; i++) { result.get(leaderBuf[i]).add(i); } result.removeIf(List::isEmpty); return result; } }