AtCoder Regular Contest 130
コンテスト前のレート:1984
レート通りのパフォーマンスが得られる順位:302位(1200点、85分53秒)
A - Remove One Character
思考過程
- 同じ文字が個連続する区間ごとに、を足していきたい。
- これは、同じ文字が個目であるごとにを足していっても同じなので(個目の文字をとした時の相方となるが通りのため)、そのように実装する。
import java.io.BufferedReader; import java.io.InputStreamReader; public class Main { public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine()); char[] s = br.readLine().toCharArray(); br.close(); long ans = 0; long cnt = 0; for (int i = 1; i < n; i++) { if (s[i - 1] == s[i]) { cnt++; ans += cnt; } else { cnt = 0; } } System.out.println(ans); } }
ここまで1分58秒+0ペナ。39位。
B - Colorful Lines
思考過程
- 普通に前からやって上書き部分を正しく処理できるか、もしくは後ろからやって一度塗られた部分は避けることを上手く処理できるか。
- 以下のようにすれば後ろからできる。
- ある行を塗ったら、その行は二度と塗れないとし(塗った行番号をSetで管理する)、次回列方向に塗る際に塗れるマスの数を減らす(を減らす)。 列を塗る場合も同様。
import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.HashSet; import java.util.Set; public class Main { public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] sa = br.readLine().split(" "); int h = Integer.parseInt(sa[0]); int w = Integer.parseInt(sa[1]); int m = Integer.parseInt(sa[2]); int q = Integer.parseInt(sa[3]); int[] t = new int[q]; int[] n = new int[q]; int[] c = new int[q]; for (int i = 0; i < q; i++) { sa = br.readLine().split(" "); t[i] = Integer.parseInt(sa[0]); n[i] = Integer.parseInt(sa[1]); c[i] = Integer.parseInt(sa[2]) - 1; } br.close(); long[] ans = new long[m]; Set<Integer> x = new HashSet<>(); Set<Integer> y = new HashSet<>(); for (int i = q - 1; i >= 0; i--) { if (t[i] == 1) { if (x.add(n[i])) { ans[c[i]] += w; h--; } } else { if (y.add(n[i])) { ans[c[i]] += h; w--; } } } StringBuilder sb = new StringBuilder(); for (long i : ans) { sb.append(i).append(' '); } sb.deleteCharAt(sb.length() - 1); System.out.println(sb.toString()); } }
ここまで8分13秒+0ペナ。80位。
C - Digit Sum Minimization
問題
下記の方法で穴がないのかはあまり自信ない。
たまたま例2で引っかかったおかげでなんとかなった。
思考過程
- 繰り上がりがなければ、どのように並べ替えようとも合計は変わらず、逆に言えば繰り上がる度に減っていくので、繰り上がり回数を最大化する問題。
- (は繰り上がりがあれば、なければ)となる組合せをなるべく多くするには、下の桁から順に、合計~の優先順で作ればよい?
- 合計~のいずれも作れなくなったら、合計~を適当に作り、の短い方の桁数を過ぎた後は、繰り上がりが維持されている可能性も考慮して余ったものを~の順に並べることにする。
- これだけだと嘘くさいとは思ったがやはり例2が駄目で、一の位がになってしまい、十の位でが作れなくなるため、一の位をにできる方法を考える。
- 一の位は、十の位以降でを作れる個数が減らないように決める方法があるならば、そのようにする必要がある。
- に含まれる~の個数から、の組合せを作れる個数を一旦引いた上で合計~が作れるかどうかを試すようにする。
import java.io.BufferedReader; import java.io.InputStreamReader; public class Main { public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); char[] a = br.readLine().toCharArray(); char[] b = br.readLine().toCharArray(); br.close(); int[] x = new int[10]; for (int i = 0; i < a.length; i++) { x[a[i] - '0']++; } int[] y = new int[10]; for (int i = 0; i < b.length; i++) { y[b[i] - '0']++; } // (1, 8)、(2, 7)、・・・分を一旦引く int[] q = new int[10]; for (int i = 1; i < 9; i++) { q[i] = Math.min(x[i], y[9 - i]); x[i] -= q[i]; y[9 - i] -= q[i]; } int min = Math.min(a.length, b.length); StringBuilder sa = new StringBuilder(); StringBuilder sb = new StringBuilder(); int k = 0; int s = 0; // 一の位 label: for (int j = 10; j < 20; j++) { for (int j1 = 1; j1 < 10; j1++) { int j2 = j - j1 - k; if (j2 < 10 && x[j1] > 0 && y[j2] > 0) { sa.append(j1); sb.append(j2); x[j1]--; y[j2]--; k = 1; s = 1; break label; } } } // 引いた分を戻す for (int i = 1; i < 9; i++) { x[i] += q[i]; y[9 - i] += q[i]; } label: for (int i = s; i < min; i++) { for (int j = 10; j < 20; j++) { for (int j1 = 1; j1 < 10; j1++) { int j2 = j - j1 - k; if (j2 < 10 && x[j1] > 0 && y[j2] > 0) { sa.append(j1); sb.append(j2); x[j1]--; y[j2]--; k = 1; continue label; } } } for (int j = 2; j < 10; j++) { for (int j1 = 1; j1 < j; j1++) { int j2 = j - j1 - k; if (j2 < 10 && x[j1] > 0 && y[j2] > 0) { sa.append(j1); sb.append(j2); x[j1]--; y[j2]--; k = 0; continue label; } } } } // aとbの桁数が異なる場合の余り分の処理 int[] z = x; StringBuilder sb2 = sa; if (b.length > min) { z = y; sb2 = sb; } for (int i = 9; i > 0; i--) { for (int j = 0; j < z[i]; j++) { sb2.append(i); } } sa.reverse(); sb.reverse(); System.out.println(sa.toString()); System.out.println(sb.toString()); } }
ここまで33分15秒+0ペナ。29位。
残り時間の大半はEに使った。
全部可能な最小値から始めるようにしたら不可能判定ができておらず、不可能になったらから始めるのがしか思い付かず。
素直にDにもっと時間を使えばよかったかもしれないが、根からDPすることしか考えていなくて、一直線でないとできる気がしなかった。
ラスト15~20分程度でFにも特攻してみて、最終形がどうなるのかの仮説まではだいたい立ったのだが、あくまでだいたい合ってるレベルで、正確には詰め切れていなかったのでやはり厳しかった。
最終結果:ABCの3完1200点、33分15秒、137位、パフォーマンス2363
レート変動:1984→2028(+44)
どこまで落ちていくかと思ったが、青落ち3回目もあっさり黄色復帰することができ、とりあえずまだ黄色でいさせてもらえるらしい。