AtCoder Regular Contest 104
コンテスト前のレート: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できそうにないなとすぐに切り捨てていたのは反省。