Codeforces #486 Div3
Editorial
A問題
考察
に含まれる整数の種類が個未満なら取り出すのは不可能
個以上の場合は
ソースコード
Submission #38839259 - Codeforces
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.NoSuchElementException; public class A { int N,K; int[] a; private void solve() { N = nextInt(); K = nextInt(); a = new int[N]; for(int i = 0;i < N;i++) { a[i] = nextInt(); } int[] map = new int[100 + 1]; for(int i = 0;i < N;i++) { map[a[i]] = i + 1; } ArrayList<Integer> ans = new ArrayList<>(); for(int i = 0;i < 100 + 1;i++) { if (map[i] > 0) { ans.add(map[i]); } } if (ans.size() < K){ out.println("NO"); return; } out.println("YES"); for(int i = 0;i < K;i++) { if (i != 0) { out.print(" "); } out.print(ans.get(i)); } out.println(); } }
B問題
考察
文字列の長さで個の文字列をソートして
が部分文字列としてに含まれているかをについてチェック
文字列の長さでソートするのはよく考えると分かる
- の場合が部分文字列としてに含まれるのはの場合のみ
- 並べ替えが可能な場合、が部分文字列としてに必ず含まれていなければいけない
ソースコード
Submission #38842064 - Codeforces
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.Arrays; import java.util.NoSuchElementException; public class B { int N; String[] s; private void sort(String[] s) { for(int i = 0;i < N;i++) { for(int j = i+1;j < N;j++) { if (s[i].length() > s[j].length()) { String tmp = s[i]; s[i] = s[j]; s[j] = tmp; } } } } private void solve() { N = nextInt(); s = new String[N]; for(int i = 0;i < N;i++) { s[i] = next(); } sort(s); for(int i = 0;i < N-1;i++) { if (s[i+1].indexOf(s[i]) == -1) { out.println("NO"); return; } } out.println("YES"); for(int i = 0;i < N;i++) { out.println(s[i]); } } }
C問題
問題
個の長さの各数列が与えられる
各数列の長さの総和は以下である
2つの数列とを選び、以下の操作が出来る
- とからそれぞれ1つずつを取り除く
操作後、数列の総和と数列の総和を等しくすることが可能か
可能な場合はとを出力する
考察
操作後の2つの数列の総和を等しくしたいので、どの数列からどの値を取り除いて数列の総和はどうなるのかをあらかじめ求めておく。(以下のようなペアを作っておく)
のペアをソートする
あとは各ペアに対してが同じでが異なるもう一つペアが存在するか二分探索
存在する場合はその2つのペアが解
ソースコード
Submission #38854484 - Codeforces
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.*; public class C { int K; int[] N; int[][] S; ArrayList<D> list; private class D implements Comparable<D> { long sum; int ij,xy; public D(long sum,int ij,int xy) { this.sum = sum; this.ij = ij; this.xy = xy; } public int compareTo(D other) { if (this.sum != other.sum) { return Long.compare(this.sum, other.sum); } if (this.ij != other.ij) { return Integer.compare(this.ij, other.ij); } return Integer.compare(this.xy, other.xy); } public String toString() { return "[sum=" + this.sum + " ij=" + this.ij + " xy=" + this.xy + "]"; } } private void solve() { K = nextInt(); N = new int[K]; S = new int[K][]; list = new ArrayList<>(); for(int i = 0;i < K;i++) { N[i] = nextInt(); S[i] = new int[N[i]]; long sum = 0; for(int j = 0;j < N[i];j++) { S[i][j] = nextInt(); sum += S[i][j]; } for(int j = 0;j < N[i];j++) { long removedSum = sum - S[i][j]; list.add(new D(removedSum, i + 1, j+1)); } } Collections.sort(list); ArrayList<D> tmpList = new ArrayList<>(); D pre = list.get(0); for(int i = 1;i < list.size();i++) { D next = list.get(i); if (!(pre.sum == next.sum && pre.ij == next.ij)) { tmpList.add(pre); pre = next; } } tmpList.add(pre); list = tmpList; for(int i = 0;i < list.size();i++) { D d1 = list.get(i); int low = i; int high = list.size(); while(high - low > 1) { int mid = high + low >> 1; D d2 = list.get(mid); if (d1.compareTo(d2) <= 0) { high = mid; } else { low = mid; } } if (high != list.size()) { D d2 = list.get(high); if (d1.sum == d2.sum && d1.ij != d2.ij) { out.println("YES"); out.println(d1.ij + " " + d1.xy); out.println(d2.ij + " " + d2.xy); return; } } } out.println("NO"); } }
D問題
考察
よく考えたら、4つ以上の点を集合に含めることが出来ないことが分かる
例として、3つの点X,Y,Zを考える
点Xと点Yの距離を
点Yと点Zの距離を
とすると点Xと点Zの距離をの形にするにはである必要がある
ここで4つ目の点Wを加えるとする
点Zと点Wの距離を
上記のを考えるとから
点Xと点Wの距離はとなり、2の累乗の形に出来ないので、3つまで点を見れば良いことが分かる
「距離」と「点X」を決め打ちして「点Xの位置-距離」または「点Xの位置+距離」に点が存在するならば
その点を集合に追加していく
ソースコード
Submission #38969303 - Codeforces
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.NoSuchElementException; public class D { int N; ArrayList<Integer> x; private void solve() { N = nextInt(); x = new ArrayList<>(); for(int i = 0;i < N;i++) { x.add(nextInt()); } Collections.sort(x); int[] ans = new int[3]; int size = 0; for(int v : x) { for(int bit = 0;bit < 31;bit++) { int small = v - (1 << bit); int big = v + (1 << bit); int ind1 = Collections.binarySearch(x, small); int ind2 = Collections.binarySearch(x, big); if (ind1 >= 0 && ind2 >= 0 && size < 3) { ans[0] = small; ans[1] = v; ans[2] = big; size = 3; } if (ind1 >= 0 && ind2 < 0 && size < 2) { ans[0] = small; ans[1] = v; ans[2] = -1; size = 2; } if (ind1 < 0 && ind2 >= 0 && size < 2) { ans[0] = v; ans[1] = big; ans[2] = -1; size = 2; } } } if (size == 0) { out.println(1); out.println(x.get(0)); return; } out.println(size); for(int i = 0;i < size;i++) { if (i != 0) { out.print(" "); } out.print(ans[i]); } out.println(); } }
E問題
問題
整数が与えられる
の桁目と桁目を交換する操作(交換操作)が出来る(交換操作後に先頭から0が1文字以上続く整数にするような交換操作は出来ない)
整数が25で割り切れる数になるように交換操作を繰り返した場合の交換操作回数の最小値を求めたい
25で割り切れる数に出来ない場合は-1を出力する
考察
で割り切れる数の下2桁に注目すると
の繰り返しになること気付くので、下2桁をその4パターンに絞る
まず、下2桁がになる場合について考える
交換操作回数を最小にしたいので、下1桁目から一番近いを持つ桁(下1桁目も含む)からを交換操作をしながら下1桁目に配置する
下2桁目も同様にを持つ一番近い桁(下1桁目は除く)から交換操作をしながら下2桁目に配置する
その後、先頭1桁目がの場合はではない値を持つ桁から、先頭に値を交換操作を行いながら配置する
下2桁がになるような最小の交換操作回数は
も同じように実際に交換操作を行いながら、交換操作回数の最小値を求める
ソースコード
Submission #39022664 - Codeforces
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.Arrays; import java.util.NoSuchElementException; public class E { char[] N; private void swapFromLToR(int l,int r,char[] ch) { for(int k = l;k < r;k++) { char tmp = ch[k]; ch[k] = ch[k+1]; ch[k+1] = tmp; } } private void swapFromRToL(int l,int r,char[] ch) { for(int k = r;k > l;k--) { char tmp = ch[k]; ch[k] = ch[k-1]; ch[k-1] = tmp; } } private long toLong(char[] ch) { long ret = 0L; for(char c : ch) { ret *= 10; ret += c - '0'; } return ret; } private int calc(char[] ch,char a,char b) { int ret = 0; int r = -1; for(int i = ch.length-1;i >= 0;i--) { if (ch[i] == b) { r = i; break; } } if (r == -1) { return Integer.MAX_VALUE; } swapFromLToR(r,ch.length-1 ,ch); ret += ch.length-1 - r; int l = -1; for(int i = ch.length-2;i >= 0;i--) { if (ch[i] == a) { l = i; break; } } if (l == -1) { return Integer.MAX_VALUE; } swapFromLToR(l, ch.length-2,ch); ret += ch.length-2 - l; if (ch[0] == '0') { int z = -1; for(int i = 1;i < ch.length;i++) { if (ch[i] != '0') { z = i; break; } } if (z == -1) { return Integer.MAX_VALUE; } swapFromRToL(z, 0, ch); ret += z; } long n = toLong(ch); if (n % 25 == 0) { return ret; } return Integer.MAX_VALUE; } private void solve() { N = next().toCharArray(); int ans = calc(Arrays.copyOf(N,N.length),'2','5'); ans = Math.min(ans,calc(Arrays.copyOf(N,N.length),'5', '0')); ans = Math.min(ans,calc(Arrays.copyOf(N,N.length),'7', '5')); ans = Math.min(ans,calc(Arrays.copyOf(N,N.length),'0', '0')); if (ans == Integer.MAX_VALUE) { out.println(-1); } else { out.println(ans); } } }
F問題
問題
数直線上でPolycarpはからに移動したい(左から右への移動のみ可能)
個の雨が降っている区間が与えられ、(この区間同士は重ならない)
さらに個の傘の位置、重さが与えられる
Polycarpは初めにから出発する時は傘を持っていない
Polycarpはからに移動する間、傘を拾ったり、捨てることができ、傘はいくつでも拾うことが出来る
Polycarpは雨で濡れたくないので、雨が降っている区間を移動している間は少なくとも1つ以上の傘を持っている必要がある
雨が降っていない区間では傘を持っている必要は無く、雨が降っている区間内で傘を交換出来る
1単位移動するごとに持っている傘の重さの総和の分だけ疲労が増加する
からに移動する際、出来るだけ疲労が少ないようにしたいので、
疲労の最小値を求める
からに移動が出来ない場合、-1を出力する
考察
傘を持っていない状態をとしてDPをする
基本的にはのように1単位ずつ移動することを考えると、複数の傘を同時に持つのは最適ではないことが分かり
どの傘をの時に持っていればよいかをさらに考えるとDPでまとめられるかという発想になりそう
実装に関しては最初メモ化再帰で実装していたがなぜかWAが取れず、結局forDPに直して通した
ソースコード
Submission #39193925 - Codeforces
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.Arrays; import java.util.NoSuchElementException; public class F { private static final long INF = (long)1e17+7; int A,N,M; int[] U; long[] P; boolean[] R; long[][] dp; private void solve() { A = nextInt(); N = nextInt(); M = nextInt(); R = new boolean[A + 1]; for(int i = 0;i < N;i++) { int l = nextInt(); int r = nextInt(); for(int j = l;j < r;j++) { R[j] = true; } } U = new int[A + 1]; Arrays.fill(U, -1); P = new long[M]; Arrays.fill(P, INF); for(int i = 0;i < M;i++) { int x = nextInt(); P[i] = nextInt(); if (U[x] == -1 || P[U[x]] >= P[i]) { U[x] = i; } } dp = new long[A + 1][M + 1]; for(int i = 0;i < A + 1;i++) { Arrays.fill(dp[i], INF); } dp[0][M] = 0; for(int i = 0;i < A;i++) { for(int j = 0;j < M + 1;j++) { if (dp[i][j] == INF) { continue; } if (!R[i]) { dp[i + 1][M] = Math.min(dp[i + 1][M],dp[i][j]); } if (j < M) { dp[i + 1][j] = Math.min(dp[i + 1][j], dp[i][j] + P[j]); } if (U[i] != -1) { dp[i + 1][U[i]] = Math.min(dp[i + 1][U[i]], dp[i][j] + P[U[i]]); } } } long ans = INF; for(int i = 0;i < M + 1;i++) { ans = Math.min(ans, dp[A][i]); } if (ans == INF) { out.println(-1); } else { out.println(ans); } } }