Educational Codeforces Round 45
Editorial
A問題
問題
個の解説ボックスと個の団体チームが存在しており、各団体チームに均等に解説ボックスを割り当てたい
をで割り切れないときは、各団体チームに解説ボックスを割り当てることが出来ない
1つの解説ボックスを解体するのに burles支払う
1つの解説ボックスを建てるのに burles支払う
各団体チームに同じ数の解説ボックスを配布したい時、支払うburlesの最小値を求める
考察
解説ボックスの数を(団体チーム数)で割り切れるまで
解体する( burles支払う)か
建てる( burles支払う)かどちらか一方を行うことを考えると
が分かる
結果的に支払うburlesの最小値はになる
ソースコード
Submission #39089978 - Codeforces
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.NoSuchElementException; public class A { long N,M; int A,B; private void solve() { N = nextLong(); M = nextLong(); A = nextInt(); B = nextInt(); long mod = N % M; long a = A * (M - mod); long b = B * mod; long ans = Math.min(a, b); out.println(ans); } }
B問題
問題
皿の上に体のバクテリアが存在する
番目のバクテリアの大きさはである
という定数が与えられる
番目のバクテリアは以下の条件を満たすとき、番目のバクテリアを食べることが出来る
食べられた番目のバクテリアは皿の上から消える(番目のバクテリアの大きさは変化しない)
最終的に皿の上に残存しているバクテリアの数の最小値を求める
考察
まず、大きさの昇順にソートする
は重複する場合があるので、同じはまとめる
大きさの昇順にを見ていき、を満たす場合
のバクテリアを除いていく
ソースコード
Submission #39101019 - Codeforces
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.*; public class B { int N,K; ArrayList<Integer> a; private void solve() { N = nextInt(); K = nextInt(); a = new ArrayList<>(); for(int i = 0;i < N;i++) { a.add(nextInt()); } Collections.sort(a); TreeMap<Integer,Integer> map = new TreeMap<>(); for(int v : a) { if (map.containsKey(v)) { map.put(v, map.get(v) + 1); } else { map.put(v, 1); } } ArrayList<Integer> b = new ArrayList<>(); for(int v : map.keySet()) { b.add(v); } int ans = N; for(int i = 0;i < b.size() - 1;i++) { int j = i + 1; if (b.get(i) < b.get(j) && b.get(i) + K >= b.get(j)) { ans -= map.get(b.get(i)); } } out.println(ans); } }
C問題
問題
個の"(",")"のみが含まれる文字列が与えられる
2つの文字列を選び、文字列結合した結果が有効な括弧文字列であるペアの数を求める
でペアとが有効な括弧文字列である場合、どちらも別々でカウントする
でペアとが有効な括弧文字列である場合、1つとカウントする
考察
3つパターンで個の括弧文字列を分ける
- 既に有効な括弧文字列である場合
- 文字列の左から順に見ていく。")"を見ている時、その文字列内で"("と")"で対応できていない")"の数が1つ以上の場合
- 文字列の右から順に見ていく。"("を見ている時、その文字列内で"("と")"で対応できていない"("の数が1つ以上の場合
後は
上記のパターンをすべて足した数が解
ソースコード
Submission #39109916 - Codeforces
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.*; public class C { int N; String[] brackets; private void solve() { N = nextInt(); brackets = new String[N]; for(int i = 0;i < N;i++) { brackets[i] = next(); } TreeMap<Integer, Integer> leftMinus = new TreeMap<>(); TreeMap<Integer, Integer> rightPlus = new TreeMap<>(); int zero = 0; for(int i = 0;i < N;i++) { char[] b = brackets[i].toCharArray(); int L = b.length; int depth = 0; int leftCnt = 0; for(int j = 0;j < L;j++) { if (b[j] == ')') { depth--; } else { depth++; } if (depth < 0) { leftCnt++; } } depth = 0; int rightCnt = 0; for(int j = L-1;j >=0;j--) { if (b[j] == '(') { depth--; } else { depth++; } if (depth < 0) { rightCnt++; } } if (leftCnt > 0 && rightCnt > 0) { continue; } if (leftCnt == 0 && rightCnt == 0) { zero++; continue; } if (leftCnt > 0) { if (leftMinus.containsKey(depth)) { leftMinus.put(depth, leftMinus.get(depth) + 1); } else { leftMinus.put(depth, 1); } } if (rightCnt > 0) { if (rightPlus.containsKey(depth)) { rightPlus.put(depth, rightPlus.get(depth) + 1); } else { rightPlus.put(depth, 1); } } } long ans = ((long)zero) * (zero); for(int m : leftMinus.keySet()) { if (rightPlus.containsKey(-m)) { ans += ((long) leftMinus.get(m)) * rightPlus.get(-m); } } out.println(ans); } }
D問題
問題
頂点数がの0と1を含む正方行列で表される無向グラフを考える
が1の場合は頂点と頂点は辺で繋がっていることを表す
無向グラフの連結成分の数が、無向グラフの補グラフ上の連結成分の数がである
無向グラフを表すことが出来るかを考える
※補グラフの説明:
補グラフ - Wikipedia
考察
とかのパターンで色々実験してみると
の場合はになることに気付く(の場合は)
これは補グラフの特徴として
無向グラフ上で辺が繋がっていない頂点同士はグラフの補グラフ上では辺で繋がることに基づく
例えば、の上で2つの連結成分が存在し
連結成分では頂点
連結成分では頂点を含むとする
の補グラフでは
頂点はと辺で繋がり、頂点もと繋がり、最終的にでは1つの連結成分となる
これででの場合は条件を満たす無向グラフを表すことが出来ないことが分かった
あとはの場合を考えると
連結成分の数がになるまで頂点同士を辺で繋げていけば良い
の場合もの時と同じ考えで解ける
特殊ケースがある
N = 2,A = 1,B = 1
N = 3,A = 1,B = 1
ソースコード
Submission #39414034 - Codeforces
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.Arrays; import java.util.NoSuchElementException; public class D { int N,A,B; private void solve() { N = nextInt(); A = nextInt(); B = nextInt(); int min = Math.min(A ,B); if (min > 1) { out.println("NO"); return; } if ((N == 2 && A == 1 && B == 1) || (N == 3 && A == 1 && B == 1)) { out.println("NO"); return; } int[][] G = new int[N][N]; if (A == 1) { for(int i = 0;i < N;i++) { for(int j = 0;j < N;j++) { if (i == j) { G[i][j] = 0; } else { G[i][j] = 1; } } } for(int i = 0;i < N - B;i++) { G[i][i+1] = 0; G[i+1][i] = 0; } } else { for(int i = 0;i < N - A;i++) { G[i][i+1] = 1; G[i+1][i] = 1; } } out.println("YES"); for(int i = 0;i < N;i++) { for(int j = 0;j < N;j++) { out.print(G[i][j]); } out.println(); } } }
E問題
問題
Adilbekの家はx軸上で表される通りに存在している
通りはとても暗いので、照らすためにいくつかの照明を設置したい
通りには照明を設置するための箇所があり、それぞれに対応している
しかし、箇所にはランプが設置出来ない
それぞれパワーの違いによって異なるタイプの照明がある
位置に設置し、パワーがである照明は区間を照らす
照明はパワーがまでの異なるタイプがそれぞれ無限個売っている
客は1つのタイプしか購入できない
パワーがの照明を購入するにはのコストが掛かる
通りの全体を照らすための照明を購入する最小コストを求める
考察
各パワーについて
箇所すべて照らせるようにを照らすように貪欲に試していく。
試していく途中でがランプが設置出来ない位置の場合は
区間内(既に設置した1つ前のランプの位置と設置出来ない位置の間)でランプが設置出来る最大の位置に次のランプを設置するようにする
との制約から間に合わないと思ってしまったが、意外と間に合う
これは各パワーを試していく中でが増加していき、ランプが照らす範囲が大きくなり、ランプを置く候補が絞られていくイメージから
ソースコード
Submission #39438365 - Codeforces
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.Arrays; import java.util.NoSuchElementException; public class E { int N,M,K; int[] s,a; private void solve() { N = nextInt(); M = nextInt(); K = nextInt(); s = new int[M]; for(int i = 0;i < M;i++) { s[i] = nextInt(); } a = new int[K + 1]; for(int i = 1;i <= K;i++) { a[i] = nextInt(); } boolean[] blocked = new boolean[N + 1]; for(int i = 0;i < M;i++) { blocked[s[i]] = true; } int[] notBlockIndex = new int[N + 1]; notBlockIndex[N] = N; int index = 0; for(int i = 0;i < N;i++) { if (!blocked[i]) { index = i; } notBlockIndex[i] = index; } long ans = Long.MAX_VALUE; for(int i = 1;i <= K;i++) { int now = 0; long count = 0; if (blocked[now]) { continue; } while(now < N) { int next = Math.min(N, now + i); int nextnext = notBlockIndex[next]; if (now == nextnext) { break; } now = nextnext; count++; } if (!blocked[now] && now >= N) { ans = Math.min(ans, count * a[i]); } } if (ans == Long.MAX_VALUE) { ans = -1; } out.println(ans); } }
F問題
問題
個の分岐点と本のパイプで構成されている水分配システムがある
番目のパイプは分岐点と間に接続されている
の場合はからに向かっての水が流れる
の場合はからに向かっての水が流れる
このを求めたい
番目の分岐点に水の流入量と水の放出量の差が定められている
の場合は番目の分岐点への水の流入量が水の放出量より多いことを表す
の場合は番目の分岐点からの水の放出量が水の流入量より多いことを表す
が上記の要件を満たすように出来るか
出来る場合はを出力し、不可能な場合-1を出力する
考察
要件を満たすを求められるかは各分岐点の放出量の総和と各分岐点の流出量の総和が等しく出来るかで分かる
適当な分岐点を決め、パイプで接続している分岐点に水を放出または、からへ水を流入すること考える
パイプが分岐点からに接続されている場合、
パイプが分岐点からに接続されている場合、
そしてから分の流量を加える
これを分岐点と接続されている次の分岐点間のパイプについて同様に考え、繰り返していき
すべてのパイプについて流量をDFS等で貪欲に決めていく
ソースコード
Submission #39543693 - Codeforces
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.NoSuchElementException; public class F { int N,M; int[] x,y; long[] s,flow,sum; boolean[] visited; ArrayList<Edge>[] graph; private class Edge { int ind, to, dir; public Edge(int ind, int to, int dir) { this.ind = ind; this.to = to; this.dir = dir; } } private void dfs(int n) { visited[n] = true; for(Edge e : graph[n]) { if (visited[e.to]) { continue; } dfs(e.to); flow[e.ind] = s[e.to] * e.dir; s[n] += s[e.to]; } } @SuppressWarnings("unchecked") private void solve() { N = nextInt(); s = new long[N]; sum = new long[N]; for(int i = 0;i < N;i++) { s[i] = nextInt(); } M = nextInt(); x = new int[M]; y = new int[M]; for(int i = 0;i < M;i++) { x[i] = nextInt()-1; y[i] = nextInt()-1; } long sum = 0; for(int i = 0;i < N;i++) { sum += s[i]; } if (sum != 0) { out.println("Impossible"); return; } graph = new ArrayList[N]; for(int i = 0;i < N;i++) { graph[i] = new ArrayList<>(); } for(int i = 0;i < M;i++) { graph[x[i]].add(new Edge(i, y[i], 1)); graph[y[i]].add(new Edge(i, x[i], -1)); } flow = new long[M]; visited = new boolean[N]; dfs(0); out.println("Possible"); for(int i = 0;i < M;i++) { out.println(flow[i]); } out.println(); } }
G問題(未解決)
問題
個の頂点を含む木が与えられる
頂点には数値が書かれている
関数は頂点と頂点間のパスに含まれる頂点(を含める)に書かれている数値の最大公約数を求める
の各整数に対しての計算結果がその整数に対応しているのペア数を数えたい