コンテスト前のレート:1755
レート通りのパフォーマンスが得られる順位:661位(500点、5分55秒)
A - Plus Minus
思考過程
の間で全探索し、条件を満たしたところで出力して終了。
- 探索範囲は、足し算と引き算しかしないのだから、
と
の範囲の
倍取っておけば大丈夫だろうと思った。
import java.util.Scanner; public class Main { public static void main(String[] args) throws Exception { Scanner sc = new Scanner(System.in); int a = sc.nextInt(); int b = sc.nextInt(); sc.close(); for (int x = -200; x <= 200; x++) { for (int y = -200; y <= 200; y++) { if (x + y == a && x - y == b) { System.out.println(x + " " + y); return; } } } } }
ここまで1分22秒+0ペナ。875位。
B - DNA Sequence
問題
問題理解に時間がかかった。
また、解説の実装に比べて回りくどいことをした。
思考過程
が間に合いそうなので、全ての部分文字列を
つずつ判定することを考える。
- 部分文字列に含まれるAとT、CとGの数が同じであれば答えにカウントしていく。
- 部分文字列(元の文字列の一部区間)に含まれる各文字の数は、累積和を使って
で求める。
- 実装上、T→B、G→Dに変換しておけば、A~D→0~3にでき、配列やループで扱いやすくなる。
import java.util.Scanner; public class Main { public static void main(String[] args) throws Exception { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); char[] s = sc.next().replaceAll("T", "B").replaceAll("G", "D").toCharArray(); sc.close(); int[][] sum = new int[4][n]; for (int i = 0; i < n; i++) { int c = s[i] - 'A'; sum[c][i]++; } for (int k = 0; k < 4; k++) { for (int i = 1; i < n; i++) { sum[k][i] += sum[k][i - 1]; } } int ans = 0; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { int[] cnt = new int[4]; for (int k = 0; k < 4; k++) { cnt[k] = sum[k][j]; if (i > 0) { cnt[k] -= sum[k][i - 1]; } } if (cnt[0] == cnt[1] && cnt[2] == cnt[3]) { ans++; } } } System.out.println(ans); } }
ここまで10分35秒+0ペナ。1074位。
まあ普通のペースかなと思いつつ順位表を見たら、予想した倍以上の順位で水パフォ見込みで愕然としていた。
5分55秒時点だと、多分やっと問題を理解した頃だと思う。
C - Fair Elevator
問題
15分ほど考えてDへ。Dが解けた後再び20分費やしたが解けず。
「区間が被っていない or が同じ」の2-SATのように見えていたが、それをtrue/falseで表すのは無理そうなどと思ったりしていた。
D - Multiset Mean
問題
方針は比較的すぐに出てきたので、この問題に集中することにし、結果的に成功した。
思考過程
- 平均に関する問題なので、
を求めるときは
~
が
個ずつあるものとして、平均が
になる個数を求めることを考える。
- まず、
だけ使うパターンが
通り。
を
個使う場合は、
も
個使う。
を
個使う場合は、
を
個か、
を
個使う。
- つまり、マイナス側とプラス側の合計値が同じになる集合を作るパターンが何通りかを求めたい。
- 「dp[i][j]:
との差の絶対値が
以下の数のみを使用し、合計値が
になる通り数」を求められるか考える。
のサイズをいくつにすればよいかだが、これは
~
の和の
倍。
のサイズ
も含めてDPテーブルのサイズは
万くらい。遷移が
ならいける気がしてくる。
- DPの遷移は、
を
個使う場合から
個使う場合までの和になるため、
となる。
- これは、mod
ごとに和を記憶しておくことで
を
にできる。(毎回
を足して
を引く)
- 答えは、各
について、
(マイナス側)と
(プラス側)を掛け合わせ、さらに
~
個の
を任意に付け足せるため、
倍する。
の場合のみ、空集合はNGのため、
通り。
※実際は、上記10で、とか、
のところを
とかやったりしてもっと迷走していた。
import java.util.Scanner; public class Main { public static void main(String[] args) throws Exception { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int k = sc.nextInt(); int m = sc.nextInt(); sc.close(); int total = n * (n - 1) / 2 * k; long[][] dp = new long[n][total + 1]; dp[0][0] = 1; for (int i = 1; i < n; i++) { int i1 = i - 1; long[] sum = new long[i]; for (int j = 0; j <= total; j++) { int ji = j % i; sum[ji] += dp[i1][j]; int d = j - i * (k + 1); if (d >= 0) { sum[ji] -= dp[i1][d]; sum[ji] += m; } sum[ji] %= m; dp[i][j] += sum[ji]; dp[i][j] %= m; } } for (int x = 1; x <= n; x++) { int l = x - 1; int r = n - x; long ans = 0; for (int j = 1; j <= total; j++) { ans += dp[l][j] * dp[r][j] % m; ans %= m; } ans *= k + 1; ans += k; ans %= m; System.out.println(ans); } } }
ここまで98分41秒+0ペナ。190位。
最終結果:ABDの3完、98分41秒、223位、パフォーマンス2249
レート変動:1755→1815(+60)
D問題を通したことで、2完早解きからも3完早解きからも逃れられて大成功。(1200点のパフォーマンス範囲は2183~2360で、時間による差は誤差みたいなもの)
C問題でDPできそうにないなとすぐに切り捨てていたのは反省。