Codeforces #371 Div2 A~C
A
考察
・区間[l1,r1],区間[l2,r2]を数直線上で考えて、[l1,r1]と[l2,r2]の位置関係でそれぞれ場合分けして,
[l1,r1]と[l2,r2]間でかさなっている区間の長さ + 1が解になる。
・kが重なっている区間内に存在する場合は長さから-1した値が解になる。
・他の人の提出を見て気付いたけれど、実は場合分けをせずにできることができる。
・min(r1,r2) - max(l1,l2) + 1が重なっている区間の長さになるになるのだけど,
min(r1,r2) < max(l1,l2)の場合は区間が重なってないので0になる。
ソースコード
場合分け
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.NoSuchElementException; import java.util.*; public class Main { long l1,r1,l2,r2,k; public void solve(){ l1 = nextLong(); r1 = nextLong(); l2 = nextLong(); r2 = nextLong(); k = nextLong(); int a = 0; if(r1 < l2 || r2 < l1 || r2 < l1 || r1 < l2){ out.println(0); } else if(l1 <= l2 && r1 <= r2){ if(l2 <= k && k <= r1)a=1; out.println(r1 - l2 + 1 - a); }else if(l2 <= l1 && r2 <= r1){ if(l1 <= k && k <= r2)a=1; out.println(r2 - l1 + 1 - a); }else if(l2 <= l1 && r1 <= r2){ if(l1 <= k && k <= r1)a=1; out.println(r1 - l1 + 1 - a); }else if(l1 <= l2 && r2 <= r1){ if(l2 <= k && k <= r2)a=1; out.println(r2 - l2 + 1 - a); } } public static void main(String[] args) { out.flush(); new Main().solve(); out.close(); } /* Input */ private static final InputStream in = System.in; private static final PrintWriter out = new PrintWriter(System.out); private final byte[] buffer = new byte[2048]; private int p = 0; private int buflen = 0; private boolean hasNextByte() { if (p < buflen) return true; p = 0; try { buflen = in.read(buffer); } catch (IOException e) { e.printStackTrace(); } if (buflen <= 0) return false; return true; } public boolean hasNext() { while (hasNextByte() && !isPrint(buffer[p])) { p++; } return hasNextByte(); } private boolean isPrint(int ch) { if (ch >= '!' && ch <= '~') return true; return false; } private int nextByte() { if (!hasNextByte()) return -1; return buffer[p++]; } public String next() { if (!hasNext()) throw new NoSuchElementException(); StringBuilder sb = new StringBuilder(); int b = -1; while (isPrint((b = nextByte()))) { sb.appendCodePoint(b); } return sb.toString(); } public int nextInt() { return Integer.parseInt(next()); } public long nextLong() { return Long.parseLong(next()); } public double nextDouble() { return Double.parseDouble(next()); } }
min,maxを取る
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.NoSuchElementException; import java.util.*; public class Main { long l1,r1,l2,r2,k; public void solve(){ l1 = nextLong(); r1 = nextLong(); l2 = nextLong(); r2 = nextLong(); k = nextLong(); long maxL = Math.max(l1,l2); long minR = Math.min(r1,r2); if(maxL > minR){ out.println(0); }else{ int a = 0; if(maxL <= k && k <= minR)a=1; out.println(minR - maxL + 1 - a); } } public static void main(String[] args) { out.flush(); new Main().solve(); out.close(); }
B
考察
・配列の値すべてがという値をそれぞれの要素に最大一回使って表せる値はの三種類しかない。
・これはにしてしまうと他の配列内の以下の値はを一回使ってもにならないため。またも同じこと。
・そして、やることはの値をそれぞれの値に出来るかどうかを試していけばよい。
・実はこれも他にもっと良い方法があって、内の要素の値の種類が2以下の場合は一方のどちらかの値に合わせれば良いのでYES,
4以上の時はをどんな値にしてもすべて同じ値にすることは出来ないのでNO,3の場合で,最小の値 = x,二番目に小さい値 = y,最大の値 = z,としたときに,
y * 2 = x + yになる場合はすべて同じ値にすることが出来る。
ソースコード
愚直解
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.NoSuchElementException; import java.util.*; public class Main { int N; long[] a; public void solve(){ N = nextInt(); a = new long[N]; for(int i = 0;i < N;i++){ a[i] = nextLong(); } Arrays.sort(a); boolean flag = true; for(int i = 0;i < N;i++){ if(a[i] == a[N - 1])break; if(a[N - 1] - a[i] != a[N - 1] - a[0])flag = false; } if(flag){ out.println("YES"); return; } flag = true; for(int i = 0;i < N - 1;i++){ if(a[i] == a[0])continue; if(a[i] - a[0] != a[N -1] - a[0])flag = false; } if(flag){ out.println("YES"); } flag = true; long mid = (a[N - 1] - a[0]) / 2 + a[0]; long pre = mid - a[0]; for(int i = 0;i < N;i++){ if(a[i] == mid)continue; long diff = 0; if(a[i] > mid){ diff = a[i] - mid; }else{ diff = mid - a[i]; } if(diff != pre){ flag = false; break; } } if(flag){ out.println("YES"); }else{ out.println("NO"); } } public static void main(String[] args) { out.flush(); new Main().solve(); out.close(); } }
値の種類をカウント
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.NoSuchElementException; import java.util.*; public class Main { int N; TreeSet<Integer> a; public void solve(){ N = nextInt(); a = new TreeSet<Integer>(); for(int i = 0;i < N;i++){ a.add(nextInt()); } boolean ok; if(a.size() <= 2){ ok = true; }else if(a.size() > 3){ ok = false; }else{ int x = a.pollFirst(); int y = a.pollFirst(); int z = a.pollFirst(); if(y * 2 == x + z){ ok = true; }else{ ok = false; } } if(ok){ out.println("YES"); }else{ out.println("NO"); } } public static void main(String[] args) { out.flush(); new Main().solve(); out.close(); } }
C
考察
・を数値化(ハッシュ化?)して管理して,インクリメント,デクリメントしていく。
・として0101,101等の値が渡されるが,上桁の連続した0は無視しても良い。
ソースコード
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.NoSuchElementException; import java.util.*; public class Main { int T; char[] c; long[] a; String[] s; int[] hashTable; public int hash(String x){ int i = 1; int j = x.length() - 1; int h = 0; while(j >= 0){ h += ((x.charAt(j) - '0')&1) * i; i <<= 1; j--; } return h; } public void solve(){ T = nextInt(); c = new char[T]; a = new long[T]; s = new String[T]; hashTable = new int[1 << 20]; for(int i = 0;i < T;i++){ c[i] = next().charAt(0); if(c[i] == '+'){ a[i] = nextLong(); }else if(c[i] == '-'){ a[i] = nextLong(); }else{ s[i] = next(); } } for(int i = 0;i < T;i++){ if(c[i] == '+'){ int j = 1; int x = 0; while(a[i] > 0){ x += (int)(((a[i] % 10)&1)*j); j <<= 1; a[i] /= 10; } hashTable[x]++; }else if(c[i] == '-'){ int j = 1; int x = 0; while(a[i] > 0){ x += (int)(((a[i] % 10)&1)*j); j <<= 1; a[i] /= 10; } hashTable[x]--; }else{ out.println(hashTable[hash(s[i])]); } } } public static void main(String[] args) { out.flush(); new Main().solve(); out.close(); } }
A,Bは無駄に実装がめんどくさい方法しか思いつかなかった&&時間を結構かけてしまったし、Cは普通に解けなかったしで残念...。
SRM 699 Div2 Hard
考察
・であり、の時,]から]に辿ることが出来るということは]と]の最小公倍数になる整数の頂点を通るということ。
・最小公倍数は以下である。
ソースコード
import java.util.*; public class FromToDivisibleDiv2{ final int INF = (int)1e9 + 7; int M; int[] d; private class P{ int first,second; public P(int first,int second){ this.first = first; this.second = second; } } public int gcd(int x,int y){ return y == 0 ? x : gcd(y,x%y); } public long lcm(int x,int y){ return (long)x * y / gcd(x,y); } public int shortest(int N,int S,int T,int[] a,int[] b){ M = a.length; d = new int[M]; Arrays.fill(d,INF); Queue<P> q = new ArrayDeque<P>(); for(int i = 0;i < M;i++){ if(S % a[i] == 0){ q.add(new P(i,1)); d[i] = 1; } } int ret = -1; while(q.size() > 0){ P p = q.poll(); if(T % b[p.first] == 0){ ret = p.second; break; } for(int i = 0;i < M;i++){ if(d[i] == INF && lcm(b[p.first],a[i]) <= N){ d[i] = Math.min(d[i],d[p.first] + 1); q.add(new P(i,d[i])); } } } return ret; } }
本番では解けなかったけど、Hardにしては実装とか考察はそこまで難しくないのかな
CODE FESTIVAL 2016 予選A D
考察
まず問題文にある式がどういうものかを考えてみる。
(左上の整数) + (右下の整数) = (右上の整数) + (左下の整数)を と考える。
そしてこの式を変形すると,
または
となる。
この変形した式が表すのは,列と列間の値の差は行と行で同じであるということで,これは行と列を逆にしても同じことが言える。
となると
という風にすべての行においてが成り立ち, 列にある値と列にある値の差は必ず一意になることが分かる。
これも行と列を入れ替えても同じことが成り立つ。
またの値との値の差もすべての行において等しいことが分かり、
これはから列と他のすべての列との差がすべての行において等しいということが分かる。
ある列を基準にし,列を0と考え,列と他の列との差をとする。
また行についても同じように考えることが出来て,ある行と他の行との差をとする。
以上のことを含めるとは行であり,列に存在する値とし、
を求めることが出来る。
適当な頂点から始めて辺を辿っていき,となることを目指し各頂点を通り,を求めていきます。
この辺を辿っていく操作は各連結成分ごとに行います。
最終的にとなっているか矛盾しているかを判定することができます。
ここで,問題の制約上各マスの値は非負整数となっているので、必ず各マスの値が0以上の値になっていなければなりません。
もし、の組み合わせが存在する場合は0以上の値に収まっていないマスが存在するので、解は「No」になります。
例)問題ページのサンプル4
まず,上記で示したように入力で与えられたN個の辺を重みにして,頂点と頂点に張る。
それから,適当な頂点を選びます。今回の例ではを選んでいます。から辿っていき,それぞれ,を求めていきます。
今回の最初に辿る先としてはとがあります。
式から,辺の重みはつながっている二つの頂点の重みの合計と同値になっていなければならないので,頂点の一方でも重みが分かっていれば,
みたいに式を変形して求めることが出来ます。
以上からとなります。
そして,となり,すべての辺についてが成り立つので、Yesとなります。
例)問題ページのサンプル2
今回も適当な頂点として、を選び,とします。
そして,最初に辿る頂点はになり,となります。
ここで、最後に辿るが問題になります。
からに辿るとになりますが,そうなってしまうとになってしまい,間の辺の重みと異なってしまうので,
今回はNoという結果になります。
公式解説
http://code-festival-2016-quala.contest.atcoder.jp/data/other/code-festival-2016-quala/editorial.pdf
ソースコード
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.NoSuchElementException; import java.util.*; public class Main { int R,C,N; int[] r,c,a; long[][] b; boolean[][] used; ArrayList<Edge>[][] graph; private class Edge{ int t,w; public Edge(int t,int w){ this.t = t; this.w = w; } } private class P{ int type,pos; long weight; public P(int type,int pos,long weight){ this.type = type; this.pos = pos; this.weight = weight; } } public void solve() { R = nextInt(); C = nextInt(); N = nextInt(); r = new int[N]; c = new int[N]; a = new int[N]; used = new boolean[2][]; used[0] = new boolean[R]; used[1] = new boolean[C]; b = new long[2][]; b[0] = new long[R]; b[1] = new long[C]; graph = new ArrayList[2][]; graph[0] = new ArrayList[R]; graph[1] = new ArrayList[C]; for(int i = 0;i < R;i++){ graph[0][i] = new ArrayList<Edge>(); } for(int i = 0;i < C;i++){ graph[1][i] = new ArrayList<Edge>(); } for(int i = 0;i < N;i++){ r[i] = nextInt() - 1; c[i] = nextInt() - 1; a[i] = nextInt(); graph[0][r[i]].add(new Edge(c[i],a[i])); graph[1][c[i]].add(new Edge(r[i],a[i])); } long[] min = new long[2]; for(int i = 0;i < N;i++){ if(used[0][r[i]])continue; Queue<P> q = new ArrayDeque<P>(); //type,pos,weight min[0] = Long.MAX_VALUE; min[1] = Long.MAX_VALUE; q.add(new P(0,r[i],0)); while(q.size() > 0){ P p = q.poll(); if(used[p.type][p.pos])continue; used[p.type][p.pos] = true; min[p.type&1] = Math.min(min[p.type&1],p.weight); b[p.type][p.pos] = p.weight; for(Edge e : graph[p.type][p.pos]){ q.add(new P(((p.type + 1)&1),e.t,e.w - p.weight)); } } if(min[0] + min[1] < 0){ out.println("No"); return; } } for(int i = 0;i < N;i++){ if(a[i] == b[0][r[i]] + b[1][c[i]])continue; out.println("No"); return; } out.println("Yes"); } public static void main(String[] args) { out.flush(); new Main().solve(); out.close(); } /* Input */ private static final InputStream in = System.in; private static final PrintWriter out = new PrintWriter(System.out); private final byte[] buffer = new byte[2048]; private int p = 0; private int buflen = 0; private boolean hasNextByte() { if (p < buflen) return true; p = 0; try { buflen = in.read(buffer); } catch (IOException e) { e.printStackTrace(); } if (buflen <= 0) return false; return true; } public boolean hasNext() { while (hasNextByte() && !isPrint(buffer[p])) { p++; } return hasNextByte(); } private boolean isPrint(int ch) { if (ch >= '!' && ch <= '~') return true; return false; } private int nextByte() { if (!hasNextByte()) return -1; return buffer[p++]; } public String next() { if (!hasNext()) throw new NoSuchElementException(); StringBuilder sb = new StringBuilder(); int b = -1; while (isPrint((b = nextByte()))) { sb.appendCodePoint(b); } return sb.toString(); } public int nextInt() { return Integer.parseInt(next()); } public long nextLong() { return Long.parseLong(next()); } public double nextDouble() { return Double.parseDouble(next()); } }
考察とか結構自分の頭の中を整理するために書いたようなものなので,他の人は分かりづらいものになったかもしれませんが,
少しでも何かの気付きの手助けになればと思い,記事にして残しておきます。
間違い,指摘等あれば遠慮なくどうぞ
Codeforces #372 Div2 A~C
A
考察
を順に見ていき,カウントしていく。
との差がより大きければカウントをリセットする。
ソースコード
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.NoSuchElementException; public class Main { int N,c; int[] t; public void solve() { N = nextInt(); c = nextInt(); t = new int[N]; for(int i = 0;i < N;i++){ t[i] = nextInt(); } int cnt = 1; for(int i = 0;i < N - 1;i++){ if(t[i + 1] - t[i] > c){ cnt = 1; }else{ cnt++; } } out.println(cnt); } public static void main(String[] args) { out.flush(); new Main().solve(); out.close(); } /* Input */ private static final InputStream in = System.in; private static final PrintWriter out = new PrintWriter(System.out); private final byte[] buffer = new byte[2048]; private int p = 0; private int buflen = 0; private boolean hasNextByte() { if (p < buflen) return true; p = 0; try { buflen = in.read(buffer); } catch (IOException e) { e.printStackTrace(); } if (buflen <= 0) return false; return true; } public boolean hasNext() { while (hasNextByte() && !isPrint(buffer[p])) { p++; } return hasNextByte(); } private boolean isPrint(int ch) { if (ch >= '!' && ch <= '~') return true; return false; } private int nextByte() { if (!hasNextByte()) return -1; return buffer[p++]; } public String next() { if (!hasNext()) throw new NoSuchElementException(); StringBuilder sb = new StringBuilder(); int b = -1; while (isPrint((b = nextByte()))) { sb.appendCodePoint(b); } return sb.toString(); } public int nextInt() { return Integer.parseInt(next()); } public long nextLong() { return Long.parseLong(next()); } public double nextDouble() { return Double.parseDouble(next()); } }
B
考察
・与えられた文字列の中で26文字の部分文字列を見つけ、A~Zの文字をそれぞれ1回ずつ使っているかを調べればよい。
・その部分文字列内の「?」の個数 = A~Zの中で使っていない文字の数であれば「?」をA~Zに置き換えて目的の文字列を作ることができる。
・もし目的の文字列が作れる場合、置き換えていない「?」はすべて適当な文字に当てはめればよい。
ソースコード
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.NoSuchElementException; public class Main { char[] c; int N; public void solve() { c = next().toCharArray(); N = c.length; int[] a; for(int i = 0;i < N - 25;i++){ a = new int[26]; int q = 0; for(int j = 0;j < 26;j++){ if(c[i + j] == '?')q++; else a[c[i + j] - 'A']++; } for(int j = 0;j < 26;j++){ if(a[j] == 0){ q--; } } if(q == 0){ for(int j = 0;j < 26;j++){ if(c[i + j] == '?'){ for(int k = 0;k < 26;k++){ if(a[k] == 0){ a[k] = 1; c[i + j] = (char)('A' + k); break; } } } } for(int j = 0;j < N;j++){ if(c[j] == '?'){ c[j] = 'A'; } out.print(c[j]); } out.println(); return; } } out.println(-1); } public static void main(String[] args) { out.flush(); new Main().solve(); out.close(); } }
C
考察
・解説見てもさっぱりだったので、とりあえずnを小さい値にして検証してみた。
X=2,K=1
X=3,K=1 (+1)
X=4,K=1 (+1)
X=2,K=2 (√)
X=4,K=2 (+2)
(略)
X=34,K=2 (+2)
X=36,K=2 (+2)
X=6,K=3 (√)
X=9,K=3 (+3)
(略)
X=141,K=3 (+3)
X=144,K=3 (+3)
X=12,K=4 (√)
X=16,K=4 (+4)
(続)
・以上のように検証していったらがレベルに到達した時のXの値になることを発見できる。
・つまりがレベル時のルートを取る前の値になる。
・が求めるべき値になる。
・しかしこのまま計算してしまうと10^18以上の値になってしまい、制約に反する。なので、に変形するとiで割れることが分かって、になって求めることができる。
・そして、iを1からNまでを舐めていき求めた値を出力する。
これ検証しても気付くの結構キツイと思う
Editorial:
codeforces.com
ソースコード
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.NoSuchElementException; public class C { int N; public void solve() { N = nextInt(); for(long k = 1;k <= N;k++){ if(k == 1){ out.println(2); }else{ out.println(((k * (k + 1)) * ((k + 1)) - ((k - 1)))); } } } public static void main(String[] args) { out.flush(); new C().solve(); out.close(); } }
AtCoderBeginnerContest 044 D
考察
解説見てAC。
・bを探索したいが,全探索をしてしまうと最大になってとなり、間に合わない。
・ここでの場合にnをb進数で表現すると2桁以下になることに気付くととの範囲に分けてbを探索できることに気付ける。
・nをb進数で表現するとなぜ2桁以下になるのかはであるのでn / bが上位桁になり,n mod bが下位桁になることから分かる。これが直観で分かりづらい方はやに具体的な値をいれて検証しましょう。(僕はこれで納得しました。実験大事!!)
・の時nをb進数で表現した上位桁をp,下位桁をqとすると
以上の式から
pが決まればbが決まりそうなので,pを探索する。
・の時はなのでbを全探索をしても十分間に合う。
公式解説:
http://arc060.contest.atcoder.jp/data/arc/060/editorial.pdf
ソースコード
import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.NoSuchElementException; public class Main { long N,S; public long f(long b,long n){ if(n < b)return n; return f(b,n / b) + (n % b); } public void solve() { N = nextLong(); S = nextLong(); if(N == S){ out.println(N + 1); return; } long ans = Long.MAX_VALUE; for(int i = 2;(long)i * i <= N;i++){ long res = f(i,N); if(res == S){ out.println(i); return; } } for(int i = 1;(long)i * i <= N - S;i++){ long B = (N - S) / i + 1; if(f(B,N) == S){ ans = Math.min(ans,B); } } out.println(ans == Long.MAX_VALUE ? -1 : ans); } public static void main(String[] args) { out.flush(); new Main().solve(); out.close(); } /* Input */ private static final InputStream in = System.in; private static final PrintWriter out = new PrintWriter(System.out); private final byte[] buffer = new byte[2048]; private int p = 0; private int buflen = 0; private boolean hasNextByte() { if (p < buflen) return true; p = 0; try { buflen = in.read(buffer); } catch (IOException e) { e.printStackTrace(); } if (buflen <= 0) return false; return true; } public boolean hasNext() { while (hasNextByte() && !isPrint(buffer[p])) { p++; } return hasNextByte(); } private boolean isPrint(int ch) { if (ch >= '!' && ch <= '~') return true; return false; } private int nextByte() { if (!hasNextByte()) return -1; return buffer[p++]; } public String next() { if (!hasNext()) throw new NoSuchElementException(); StringBuilder sb = new StringBuilder(); int b = -1; while (isPrint((b = nextByte()))) { sb.appendCodePoint(b); } return sb.toString(); } public int nextInt() { return Integer.parseInt(next()); } public long nextLong() { return Long.parseLong(next()); } public double nextDouble() { return Double.parseDouble(next()); } }
競技プログラミングTODO#1
なんか競技プログラミングでやりたいことを明確に文字に起こした方がモチベが上がるかもという試みです。
TODOが達成出来たり,他のやるべきことが出来たらまた書くかもしれないので、#1ということで。
- Codeforces とりあえず20回分ぐらいのA~C(出来たらDまで)埋める。
- AOJ AOJ-ICPCを350まで埋める,VirtualArenaで良さげな問題集を見つけて解く。
- ACPC,RUPCの問題を復習
- ABC D埋め
- ARC B埋め
- AGC Cまで埋める
- yukicoder ☆2埋め,☆3半分くらい埋める。
- 蟻本 初級編,中級編の熟読and練習問題解き。
割と自分でもかなり目標高めのTODOを設定したつもり。
すべてやりきるのはだいぶ辛いと思うけど,出来たらかなり実力付くと思う。
CODEFESTIVAL2016予選Cまでにある程度達成出来たら良いな。
会津大学競技プログラミング合宿2016参加記
はじめに
3月にあったRUPC2016で中々良い思いをさせてもらったので、調子に乗って大学生ではないですがACPC2016に参加させていただきました。
tookunn.hatenablog.com
この記事を見た合宿参加者はぜひ参加記を書いて楽しかった思い出を共有しよう!!
1日目
会津大学のある福島県は僕の住む県に隣接しているので当日に在来線に乗って会津若松駅まで行きました。
会津若松駅で@ctylさんと合流し会津大学に向かいましたが早く着きすぎたためお昼を近くのラーメン屋でお昼を済ませてから再度会津大学へ向かいました。
そして、参加費を払い名札を手に入れるフェイズになった際に,名札の紐が緑,青,黄色,赤となっていてレートの色に対応しているのかという気持ちに勝手になり、自然と緑を選んでしまった...。
レートが緑なので緑。 pic.twitter.com/76N5cvraFu
— tookunn (@tookunn_1213) September 17, 2016
チーム決めフェイズを終え会津大の方2人とチームを組ませていただき立命館大学セットをしました。
会津合宿1日目
— tookunn (@tookunn_1213) September 17, 2016
チーム名「somentokunKT」で@tookunn_1213 + @kzyKT_M + @somennagasi で出ます!
最初に@somennagasiさんがAをAC。僕はBを担当して1WAを出してAC。@kzyKT_MさんがC,Eを考察しコーディングまで行っていましたが,残念ながら2完で終わりました。
もう少し僕にC,Eを一緒に考察できる実力があればよかったのですが...。申し訳なさ。
解説を聞いた後,人生初タクシーに乗って,会津若松駅に行き,@ctylさん,@yurahunaさん,@kenkooooさんと付近の中華料理屋で夕食を済ませました。
その後@kenkooooさんとは駅で別れ,残りの3人で同じ宿を取っていたので,限界集落にある宿に向かうために電車に乗り,宿の最寄り駅で下車し宿に向かいました。
こちら限界集落ですこんにちは
— ゆらふな (@yurahuna) September 17, 2016
宿では到着してすぐにお風呂に入った後,22:35からcodeforcesがあったので3人で一緒にでました。
こちら限界集落こどふぉオンサイト会場です。 pic.twitter.com/UQuBzxR5aN
— ctyl (@ctyl_0) September 17, 2016
競プロ勢3人集まってcodeforcesに出るので実質オンサイト
— tookunn (@tookunn_1213) September 17, 2016
実はcodeforcesに取り組んでいる最中に限界集落にありがちな大きい虫が度々我々3人の邪魔をしてきて辛かった。
codeforces後は即,寝床に着きました。
2日目
2日目はまず,少ない本数の電車に乗るために早起きをして,早々と会津大学へ向かいました。
そして,チームが決まり,立命館の方2人と組ませていただきました。ちなみに2日目は会津大学セットでした。
二日目はチーム「Lost_my_way」で出ます。@tookunn_1213 + @sakisaka_4geru + @1118yoshikawa
— tookunn (@tookunn_1213) September 18, 2016
チーム名の由来としては@1118yoshikawaさんがよく迷子になったり,物をなくしたりするらしくてそこから持ってきました。
コンテストの内容としてはAを@1118yoshikawaさんと@sakisaka_4geruさんに任せてAC。Bは僕が担当してAC。Cを@sakisaka_4geruさんにお願いしていて,dpっぽいというヒントをいただいて,僕が実装してAC(最近dpの問題を多めにやっておいてよかった感)。後は3人で問題を色々見ながらDは何かdfsで行けるのではと思ったけど,通らなくて他の問題を全員で見つつ終了。3完。
3人で集中して1問に取り組むスタイルでやってチームとしてコミュニーションが多く取れたチームだったので良かった。
解説を見てDをAC。ダイクストラ法をするだけだったので解きたみが強かった。
解説終了後は懇親会がありました。
懇親会!! pic.twitter.com/NCKGuS2Ov1
— tookunn (@tookunn_1213) September 18, 2016
懇親会ではお酒も入り,どんな物事,出来事に関しても競プロっぽい要素をいれていてとても勉強になる会話が飛び交っていた。
競プロでは定数倍は小さいが現実の物事にしてみると2倍,3倍はやばいとかN人の@public_sateさんがいる等々(他にもたくさんあるが紹介しきれず)。
日頃,あそこまで競プロ要素を取り入れた会話を聞かないのでとても楽しかった。
そして写真撮影は@kenkooooさんの「AOJサイコー!!」という掛け声とともにパシャリ。
その後,限界集落に向かう電車の終電が近かったので早々に懇親会会場を後にしました。
3日目
3日目は電車の都合で会場の到着がチーム決めフェイズが終わった後に着きそうだったので,あらかじめチームメンバーをTwitterで募集していたら,
@Yazatenさんが声を掛けてくださって,@Yazatenさんと@dohatsutsuさんのチームに拾ってもらえました。
会津合宿day3にチームenergy_star ( @dohatsutsu + @tookunn_1213 + @Yazaten ) で出ます!
— やざてん (@Yazaten) September 19, 2016
まず,Aを@Yazatenさん,Bを僕,Cは@dohatsutsuさん,という感じでそれぞれ取り掛かってAC。その後僕はEを眺めつつ考察をずっとしてて,実装のイメージがつかめなくてほぼ座っているだけ状態になってしまっていた。
そんな状態の間に@Yazatenさんと@dohatsutsuさんが次々ACを重ねていってE以外をすべて解いていて強かった。
でも決してお二人は僕を置いてきぼりしないで,今自分たちがどういう問題を解いているかを丁寧に説明したり,Eを一緒に考えてくれたりしてくださって僕もあきらめないでEに取り組めたので良かった。
コンテスト終了後,気付いたらオンサイトとオンライン含めて2位になっていて、非常にありがたいことになっていた。
@Yazaten さんと @tookunn_1213 さんとで energy_star というチームで参加していました。オンラインで2位という好成績。
— 怒髪 (@dohatsutsu) September 19, 2016
そして解説を聞き,記念撮影の後,解散をして無事ACPC2016が終了しました。
感想
今回の合宿はRUPC2016以来のリアルに競プロerと触れ合える機会であり、チーム戦だったので、とても楽しかった。
会津若松までの移動も比較的近かったのでとても良かった。
そしてどの大学の問題セットも個人的に良い問題が多くて実りがあった気がする。
僕が泊まった宿は限界集落など色々twitter等で言っていたが、宿のオーナーも良い人だったし、宿の雰囲気もとても良かったので結果としては良い宿でした。
ただ、今回みたいな合宿という目的がある場合は駅前の宿を取った方が移動やその他諸々がラク。
RUPC,ACPC共に僕みたいなICPCを経験したことも無ければ、大学を経験したこともない緑コーダーがここまで楽しめたのだから
まだ合宿に参加したことのない競技プログラミング初心者(僕を含め)等も是非合宿に参加してほしいなと思います。そこで是非僕とチームを組みましょう!!
個人的な思いとしては来年からは社会人なのですが、当然競技プログラミングを続けようと思っていて、
仕事,生活的に余裕があればRUPC,ACPC等にも積極的に参加していきたい(周りから老害と言われ続けるまでいや、むしろ言われ続けても)と思っています。
次参加するときは出されたA,B,C問題だけでなくD以降の難易度の問題も解けるようになっていたいですね。
合宿に参加された各大学の皆さん,社会人の皆さん,本当に3日間お疲れさまでした。
学生の皆さんとは是非CODE FESTIVALでお会いしたいですね。