足跡-sokuseki-

りかの日進月歩の記録

HUPC2019 参加記

北海道大学プログラミング合宿 2019 : ATND に参加しました。参加記FAを目指します。(追記:FAできませんでした)

経緯

○○大学競技プログラミング合宿といえば、RUPCとACPCがあります。その2つの合宿は、近年は立命館大会津大・北海道大がコンテストの問題セットを提供しており、よく懇親会などで「北海道大学はHUPCを開催しないんですか〜」みたいな話をしていました*1

しかし、ここにも書いたように、競プロ合宿の需要が高まっていることもあり、北大の方がやる気を出してくれて、開催することになりました*2
北大には競プロ合宿やその他オンサイトで知り合った人がたくさんいるので、ATNDが公開されたらすぐに登録しました。

day0

国内予選の翌日ですが、当日入りをすると早朝の飛行機でつらそうなので前日入りをしました。

day1

前日入りをしていたので朝が暇で、開場より少し早く行ったんですが、それでも運営でない参加者がすでにいてすごかった。
自己紹介フェーズの「国内予選突破できなかったので懇親会で発散します」「国内予選突破できたので懇親会で発散します」がおもしろかったです。
詳細は書きませんが、競プロ合宿はコスプレ会場でもあったんだなあと思いました(小並感)(4ヶ月ぶり3回目)。

チームは事前にてんぷらさんと組むことにしていて、残り一人をランダムに決めた結果、スポンサーのフィックスターズのMatsudaさんと組むことになりました。



〜以下コンテスト〜
てんぷらさんが後半のFAとる!って意気込んでた。
競プロがほぼ初めてのMatsudaさんがA問題、自分がB問題、てんぷらさんが後ろからといていくことにする。
Matsudaさんがつらそうで、Bも数学でつらくて、てんぷらさんがFの解法浮かんだとかいい始める。PC空いてるのでとりあえずゆっくり実装してもらうことにする。Bはそれぞれの数について2つ目の条件を満たすかをいろいろ書いて確かめると、約数が少なすぎるとだめっぽいことがわかる。2から20くらいまで書いたところで、約数が自分を除いて4つあればできそうな気がしてくる。証明してないけどてんぷらさんに相談してみるとそうだねってなって、前計算はエラトステネスの篩っぽく自分の倍数に加算していくと素因数分解とか必要なくて簡単に書けると言われたのでそれをする、AC。
Aはつらそうだけど、方針を聞くとあってそうなので、そのまま任せてC以降を読むことにする。
Cは構文解析なのでやりたくないですと言ってとばしてDを読むと、AがBの約数のときは-1で、あとはBを使わずにAだけで少なくなるかみたいなのを考えると良くて、っててんぷらさんに伝えたら書いてACしてくれた。
Aを書いてもらう間にてんぷらさんとEを考えると、てんぷらさんが(s,t)を聞いてから(s,i)と(i,t)をみるとiが最短路上にあるかわかるので、最短路上にあるやつだけをもう一度クエリ投げてパスを1つに確定するって言っててすごいなあとなる。
Aを提出すると3重ループしてdを決めた時に負になる場合の処理をしていなかったのでWA、すぐになおしてAC。
EもAC。オンサイトFA!!
Cを考えると、構文解析をしながら、短絡評価できるかをパラメータとしてもっておけばできるっててんぷらさんが言ったから書いてもらった。その間FGをみてMatsudaさんといろいろ考える。TLEしたけど状態の持ち方を変えるとACした。Fはてんぷらさんの方針(つらそう)をきいてから実装をしてもらって、てんぷらさんが実装している間2人でもっと簡単に解けないかを考えてた。けどあまりいい方法が浮かばなくて、そうしているうちにてんぷらさんがFを通してオンサイトFAをとる。
残ったGは何もわからなくて、計算量がアになっていいなら根を決めて木DPなんだけどなーとか言ってた。でも順位表を見るとうしたぷにきあくんがGをいっぱいWAってて、うしくんがいてこんなにWA出す?とかてんぷらさんと話してた。
うしたぷにきあくんがACしたあたりで、全方位木DPが〜とか言ってると、てんぷらさんが去年の国内のHに似てるっていい始めて、解説記事や講評を読んでいると、前原先生のQiitaにたどり着き、てんぷらさんが読解して、これ実装したら10^9くらいになるけど解けるのでは?って言って実装し始める。直前で書き終わって提出するもWA。全完できずにコンテスト終了。

〜以上コンテスト〜

感想戦をしてから、解説を聞く。


解説が面白すぎるんだよなあ。問題については、個人的にEが好きでした。

その後、懇親会会場まで移動する。おいしくていろんな話もできて楽しかったです。


AGCに出るために早抜けした人がちらほらいたんですが、AGCが30分こどふぉっておもしろかったです。

day2

夜はあんまり眠れなくて起きられるか不安だったんですが、無事起床。


会場についてお菓子をもぐもぐしたりする。
チームを事前に組んでいたので、チーム決めの時間にアニメを見ていました(迷惑なのでイヤホンをしようね)(ごめんなさい)。(追記:見ていたアニメはリステです )
チームメイトはえびちゃんとしるにゃん。

〜以下コンテスト〜
AのFAを担当しますと啖呵を切ってしまったのでAを読む。読んでる最中にBがAと問題設定が同じと聞こえたので、C以降を読んでもらうことにする。
A書いたんですが、バグらせて1WA。すぐに直してAC。FAはとれませんね。
Bを考えるとぜんぜんわからなかったのでえびちゃんと考えていると、しるにゃんがDわかったっぽいことを言っていたので、コーディングを交代する。
サンプルがあったぽいので投げてもらうとTLE。Bは4隅に近いやつだけピックアップしてから2乗かけて試すとよさそうだとわかり、しるにゃんに代わってBを書く。AC。
Dは2べきで考えるとよさそうとなってそのままAC。オンサイトFA。
その後えびちゃんからCの概要を聞くも、ゲームが得意ではないのでわからず、全探索するくらいしかわからないーとか言って、放置してE以降をすることにする。
ぜんぶ読んで、一番できそうだったEを考える。よく考えると、頂点1からパンを買うまで、パンを買ってからジャムを買うまで、ジャムを買ってから頂点1までに分けて考えることができると気づく(今日の最大の貢献)。頂点1からの距離を最初に求めて、あとはパンからジャムまでをいい感じに求められるといいな〜とか言ってた。頭がないので「パラメータが2つだとCHTみたいだねー」とか適当を言ってたら、しるにゃんがパンを買った時のコスト(パンの幸福度-距離)を初期値にして各ジャムまでダイクストラみたいにわーってできない?という天才の発想をしたので、えびちゃんにそれを書いてもらう。ちょっとバグったけど、なんとかAC。オンサイトFA。
FGHよりも明らかCが解くべきなので、Cを3人で考える。ゲームがわからないときはとりあえずやってみるという精神で、えびちゃんと実際に対戦する。しるにゃんは黙々と規則性を考えてた。ゲームが1試合終わっても何も得られなかったので、えびちゃんにとりあえず愚直解をかいてもらって、小さいケースで規則性考えようってなった。えびちゃんのコードをちょくちょく見ながらFを考える。すると、途中でしるにゃんが、「奇数が2つ以上あると、最初に真ん中をとってあとは対照的に動くと最適戦略」と言ったので、それをえびちゃんに書いてもらう。AC。すごい。
この時点で4完で、オンサイトには5完も出ていて、順位表からEとFのAC数が同じくらいだったので、どうしてもFをときたい!という強い意志が生まれる。
いろいろ考えると、Biでまとめて計算するのと、Aiでまとめて計算するのをして、包除で計算できない?みたいな話になる。でも計算量的にやばそう。そのあともいろいろ考えてみたけど、何も浮かばず。「こういうのはwriterの気持ちになるとよくて」「じつは全部包除なのでは?」「F包除G包除H包除」「A包除B包除C包除……」「A包除まじ?!」みたいな謎会話をしていた。最後はCEを使って
f:id:wk1080id:20190715225012p:plain
f:id:wk1080id:20190715225015p:plain
f:id:wk1080id:20190715225013p:plain
という遊びをしていました(ごめんなさい)。

〜以上コンテスト〜

感想戦をして解説を聞く。
「998244353 で割ったあまり」が多かったから実は全部writerてんぷらさんでしょとか言ってたけど全然そんなことなかった(それはそう)。

その後、解散してお片づけをした。お片づけの途中、えびちゃんと廻小宮ごっこをしてた。
一度家に帰ってから、しるにゃんとえびちゃんとわくくんと4人でゲーセンに行って遊んだ。
そのあとしるにゃんと別れて、3人で回転寿司を食べにいった。おいしかった。




寿司が流れてくるの面白かった。寿司と一緒にデザートも流れて来てさらに面白かった。3人で注文のタッチパネルのバグ探し(?)みたいなことしてて、オタクか?とか言ってた。
そのあとさらにゲーセンに戻ってお金をたくさん溶かした(ア

さいごに

今夜も1泊するんですが明日は特に何もないので、参加記はここまでにします。HUPC全体的にとても楽しかったです。チームでたくさん考察できたのも良かったし、いろんな人と交流できて良かったので、機会があればまた来たいです。

HUPC開催前に「北海道で開催しても誰も来ないんじゃないか」という話があったんですが、少なくともHUPCは30人以上が全国から集まって来たので、もうどこで合宿を開催しようと競プロ狂は来るんじゃないかと思っています。
合宿開催したいけど運営できるか不安ですみたいな人は気軽に相談に乗ります!いろんな競プロ合宿があったら楽しいよね!各地での開催を待っています!!!!

*1:開催時期的な問題や、年3回も作問をしなければならない負担、会場が北海道であることなどの懸念事項があり実現には至っていませんでした

*2:実はそすうさはRUPCでの運営経験を買われて、HUPCの運営の相談に乗る役をしていました。

ICPC2019 国内予選 参加記

noy先輩Hao君と一緒に「UnRated」というチームで出場しました。
3完54位でした。
f:id:wk1080id:20190713022124p:plain

〜前日

チーム練は3回くらいしたと思います。
HCPC 2019 Virtual Vol.20 - 足跡-sokuseki-
ICPC2019模擬国内予選 - 足跡-sokuseki-
four-t practice 2019 Vol.12 - 足跡-sokuseki-

国内突破には4完が必須なので、ABCを早くACしてD以降の考察に時間を割きたいと思っていました。
何度かチーム練して、ABCを自分とnoy先輩で考察&実装、D以降をHao君に考察してもらう戦略を立てました。
自分は今年でICPC引退なので、悔いの残らないようにしたいなあと思って個人でAOJ-ICPCをいっぱいときました。

コンテスト前

15時ごろに大学に着きそうだったので2人にpracticeを任せる。
ライブラリを印刷したやつと蟻本とティッピーを持って部屋に行く。

実装練習にICPC2017国内Cを解く。
チーム練では自分のPC(JIS)を使っていたのですが、突然外付けUSキーボードを使うことになり焦る。
さらに、プリンタを接続して印刷テストしようとしたらPC側でプリンタを認識してくれなくて、これどうするの?使うPC変える?とかいう話になる。(3人はみんなMacBookだけどエディタ等の環境がバラバラすぎるのでア)
いろいろググったりして試行錯誤したところ、開始20分前くらいにうまく認識してくれるようになったので、一安心。
ぞいぞい。

コンテスト

ACを自分が、Bをnoy先輩が、DをHao君が担当することにして、Aから読む。やるだけなので書く。AC。Bの方針を聞いて良さそうなので書いてもらっている間にCを読む。
Cがちょっと難しそうなのでHao君と一緒に考えると、右に載せる分銅と左に載せる分銅をビット全探索すれば0かどうかの判定はできることがわかる。1つ追加して〜のところがよくわかんないなーとか言ってるうちにBがかけたみたいなので見る。answerとprogramをまちがえそうになりながらもAC(複数人で提出チェックしててよかった)。
Cは右と左を全探索すると、そのとき必要になる分銅が一意に決まるので、その重さの分銅がすべてのAiで必要であればそれが答えとなりうるみたいな考察をして、実装する。Hao君に3^Mって言われたけど、計算量的に4^Mでも大丈夫そうだったので、4^Mを書く。


↑いかにもすんなり通りましたみたいな書き方をしているんですが、実はデバッグ出力と答えを見間違えていて「は?答えが出力されてないやが」とか言いつつ、解法が出てたDに実装を変わったりして、20分ほど溶かした(バカか?)。
DはCを実装している間にDP解が浮かんだらしくて、C終わった後に聞いたけどよくわからなかった(は?)。E以降を読んで解けそうなのを探したりしてると、Dのサンプルが合わないらしいので、Dを一緒に考えることにする。Dは区間add区間minの遅延セグ木でできるんじゃない?とかいう嘘解法をはやしつつ順位表を見てみるとEが0ACでFにACがでているのでFを考えてみる。FはAtCoderぽいな〜(Dもだけど)とか言いつつわからないのでDに戻ってくる。順位表をみるとEもACがでてきたので、noy先輩にEを任せてDの遅延セグ木解のコーナーを探す作業をしてた。コーナーみつからないのでサンプルあうか試そうとおもってコードを書いていると、Eは実装激重やるだけゲーらしいのでPCをnoy先輩に譲る。ここで残り45分くらい。Dは諦めてHao君とFを考えてた。
ラスト1分くらいでEの実装が終わったけど、サンプルが合わず終了。

コンテスト後

4完がアジアボーダーだと思っていたのですが、4完以上のチームが少なく、3完でもアジア行けそうな感じがする。
焼肉を食べた。


感想とか

Cのバカがなかったら10個くらい順位上がってたので泣いてる。
ICPC引退が(たぶん)半年延びたので嬉しいです。もっと精進したいです。

four-t practice 2019 Vol.12

https://onlinejudge.u-aizu.ac.jp/beta/room.html#fourt_2019_12/info
チームでときました

ABCを自分とnoy先輩、D以降をHao君が読むことにする。
Aを読む。やるだけなので実装する。AC。
Bを書いてもらう。入力形式がアでつらそう。その間Cを読む。なんだかんだBが通る。開始20分くらい。
Cは実は解いたことがあったけど実装することになる。実装つらいんだよね〜とか言いながら書く。その間noy先輩はHao君と一緒にDを考えてもらう。
Cの実装が終わってサンプルを試しても合わないので、Dを書いてもらうことにする(といいつつ、全探索しかわかんないっぽい状況だった)。
デバッグをするとlower_boundとかupper_boundのあたりがまずそうなのでかわってもらう、サンプルがあったので投げる、RE。intじゃだめなことに気づいてもう一回投げる、WA。完全にわからなくなる。ここで1時間20分くらい。
Cがわからなくなったので、Cを捨ててDを一緒に考えることにする。Dは答えが8より大きくならない(1文字ずつ区切った場合、最大が9で最小が1になる)ので、A桁で分割したあとにありうる分割の桁数はA-1, A, A+1 くらいしかないんじゃないかって話になってたんだけど、「0」は使われないのでA>2のときはAでしか分割できないのでは?となって、A>2の場合はNの約数だけ考えることにする。A=2のときどうすればいいかよくわかってなかったんだけど、Hao君がいい感じの案を思いついたらしくて、全部実装してもらうことに。ばちゃ開始から2時間15分後、見事DをAC!!わーい!

反省

一度ACした問題は、バグらせずに解けるようになりましょう(終わった後昔のACコード見たけど同じことやってるんだよね、いまだに今日のコードのだめなところがわかりません、たすけて)

ICPC2019模擬国内予選

問題文:
http://icpc2019.jag-icpc.org/icpc2019/contest/problems_guest_ja.php
順位表:
2019/Practice/模擬国内予選/順位 - ACM-ICPC Japanese Alumni Group

チームUnRatedで出てABC3完75位(有資格者46位)でした。
BCあたり時系列ちょっと怪しいですが、コンテスト中を書きます。

コンテスト

Aを自分が、Bをnoy先輩が、CをHao君が担当することになる。
Aは見たらわかるので提出、AC。Bは場所と沼地の個数をもってbfsらしいので書いてもらう、Cが読解がやばいらしいので一緒に読む。
Bは実装がつらそうで、Cはx軸とy軸独立に考えたら良くて、偶奇で良い感じにできるので、先にCを書く。WA。
Cのコーナーを考えつつBを書いてもらう。BつらそうなのでDを考える。
Dは回転だけ最初にしてそのあと編集距離を求めればできそうで、書きます。投げます。WAになります。ここで1時間経過。
BはそのあといろいろがんばってもらってAC。
Cは実験しようということになって、Cのコードをかいてもらう。20くらいまで実験すると規則性が見えます。Cが通ります。
Dのコーナーがわかって、削除してから回転したほうが得な場合があって、でもそれをどうしたらいいかわからなくなったので、先を読みます。ここでコンテスト半分くらい。

E:Mが小さいので半分全列挙とかするのかな、いや何もわからねえ
F:構文解析マジ?と思ったら文字列数え上げじゃーん、むり
G:一番長いやつから1つ内側にはいると2番目になりませんか?どうなんですか?みたいなことを考えていた
H:グラフだし(部屋、コイン)で拡張ダイクストラしたらできませんか?とか考えてた

なんだかんだ自分にはHが一番できそうだったのでHを考えると、まずコインボタンは途中で押す必要がなく、脱出直前にどの部屋のボタンを押すかを考えればよくて、これは昨日のABC-D。よって、(今いる部屋、通った部屋の数、ワープで得たコインの数)を持ってDPをして、 d_i にきたら、「e_i - ワープで得たコインの数」を「通った部屋の数」に分割するcombinationを求めて答えに足せばいい、みたいになる。しかし、状態が2000*2000*6000になって配列で持てないので、 a_i < b_i を使ってクエリ先読みして、各部屋でその都度求めることにする。あとdp[2][2000][6000]もつらいのでpriority_queueでがんばる。ここまで考えた時点で残り1時間で、とりあえずコードを書き始めたんだけど、途中でcombinationの引数が1e9までなことに気づいてつらくなる。combination以外を書いて、どうするかかんがえることにする。残り30分くらい。
FができそうらしいのでHao君にバトンタッチする。
combinationの第二引数は高々Nなので、階乗の逆元だけ前計算することにして、分子はO(N)かけて求めて計算機の力を信じることにする。ラスト10分になってFつらそうなので変わってHを書く。サンプルがいくつか合わなくて終了。お疲れ様でした。

反省など

Cですぐ実験できなかったところ
多少時間がかかってもいいから全探索するという選択肢が頭になかった
ABCあたりを高速に通したい

HCPC 2019 Virtual Vol.20

チームで解きました。
onlinejudge.u-aizu.ac.jp

Aを自分が、Bをnoy先輩が、CをHao君が担当することになったので、まずAを読む。
やるだけなので書く。ACしたのでBを書いてもらう。その間Dを読む。
Bが通ったのでCを書いてもらう。Dは拡張ダイクストラをすればできそう(最近拡張ダイクストラいっぱい書いてるので嬉しい)。
Cバグらせてつらそうだったけど、なんとかなってACしたのでDを書く。ライブラリ写経つらい。
Dも難なくACしてこの時点で開始40分くらい。
Dを書いてるうちに、2人がEの考察をしてくれていて、Eはdfsで全探索すればいいらしくて、noy先輩に実装を任せる。
FGHを読んで、Fを考えてみるけど、3^40はつらいなあとか言ってた。HはHao君がフローでできそうと言ってたんだけど、3000*3000頂点がつらいってなって、もうちょっとかんがえると、DPでできそうって言われたので、次元を増やしたらできるんじゃない?とか適当なことを言って考察を任せることにした(最悪)。Gを考えることにする。
Eが実装つらそうだったけどAC。ここで1時間40分。
Hao君にHの実装を任せて、FとGの考察をnoy先輩と2人で考察してわかんないって言うやつをした。一応2時間ばちゃということだったから2時間すぎたあたりで若干感想戦みたいなことを周囲としていた(最悪)。
Hは開始から2時間20分くらいで通りました。遷移がつらそうだったけど、コード長さはそこまで長くない(でも実装できるのつよい)。

初見のセットでのチーム練ははじめてだった*1けど、いい感じかなーっておもいました(小並感)

*1:前回の第一回目は去年の国内予選をした

AOJ2333 僕の友達は小さい

AOJ-ICPC 500 自力AC!!!!

My friends are small | Aizu Online Judge

問題概要

 N 人の友達がいて、  i 番目の友達の重さは  w_i である。
この友達を好きな順で選択し、選択した友達の重さの総和が  W を超えないようにしたとき、選択した友達の組み合わせは何通りあるか。ただし、選択できる友達が残っている場合はその友達は選択しなければならない。

制約
 1 \le N \le 200
 1 \le W \le 10^4
 1 \le w_i \le 10^4

解法

「選択できる友達が残っている場合はその友達は選択しなければならない」の制約がない場合は普通のナップサック問題となり、

dp[i][j] := iまで見て重さの総和がjのときの場合の数

とすればよい。

「選択できる友達が残っている場合はその友達は選択しなければならない」を言い換えると、「選択した友達の重さの総和 + 選択してない友達の最小の重さ  > W を満たさなければならない」となる。
よって、選択していない友達のうち、重さが最小の情報を保持してあげればよい。

dp[i][j][k] := iまで見て重さの総和がjで、選択していない重さ最小の友達のindexがkのときの場合の数

とすると、DP後で  j + w_k > W を満たす dp[n][j][k]のみを答えに加算してあげればよい。
計算量は  O(N^2W) となって間に合うが、dp[200][10000][200]では配列が足りなくなるので、1次元目を使いまわしてdp[2][10000][200]とすればよい。

AIZU ONLINE JUDGE: Code Review

AOJ 2642 Dinner

Dinner | Aizu Online Judge
AOJ-ICPC 550点…?

問題概要

 N 日間の夕食を食堂か自炊のどちらかで済ませる。
 i 日目に食堂で夕食をとると幸福度が  C_i 得られる。
各日に自炊をすると得られる幸福度は、 (自炊をした時点での自炊パワー)\times P である。
自炊パワーは、初期値が  Q であり、食堂に行くたびに 1 減り、自炊をするたびに 1 増える(食事の終了時に変動する)。
 N 日間の幸福度の総和の最大値を求めよ。

制約

 1 \le N \le 500,000
 0 \le P \le 500,000
 |Q| , |C_i| \le 500,000

解法

気づくべき重要な点は、ある日に自炊によって得られる幸福度は、「その日以前に何日自炊し、何日食堂に行ったか」のみに依存するということである。
自炊を  x 日行い、食堂に  y 日行ったとき、  x+y+1 日目に自炊をすると幸福度は  (Q+x-y)P 得られる。


ここで、  N 日間で  K 日自炊したときの幸福度を式にしてみる。
 sum := C_0 + C_1 + … + C_{N-1} とし、
自炊した日を  a_0 日目,  a_1 日目, … ,  a_{K-1} 日目(0-indexed)とする。

 a_i 日目以前に自炊した日数が  i 日で食堂に行った日数が  a_i - i 日なので、 a_i 日目の自炊パワーは、 Q+i-(a_i-i) = Q - a_i + 2i となる。
よって、  a_i 日目に自炊したときの幸福度は  (Q - a_i + 2i)P であり、  K 日の自炊で得られる幸福度は \displaystyle \sum _{i=0}^{K-1} (Q-a_i+2i)P である。
一方、食堂で得られる幸福度の総和は  sum - \displaystyle \sum_{i = 0}^{K-1} C_{a_i} である。

以上から、自炊した日を  a_0 日目,  a_1 日目, … ,  a_{K-1} 日目としたときの幸福度の総和は
 sum - \displaystyle \sum_{i = 0}^{K-1} C_{a_i} + \sum _{i=0}^{K-1} (Q-a_i+2i)P
となる。
これを変形すると、
 sum - \displaystyle \sum_{i = 0}^{K-1} C_{a_i} + \sum _{i=0}^{K-1} (Q - a_i + 2i)P
 = sum +  \displaystyle \sum _{i=0}^{K-1} \{(Q - a_i + 2i)P-C_{a_i} \}
 = sum +  \displaystyle \sum _{i=0}^{K-1} (QP - a_iP + 2iP-C_{a_i} )
 = sum +  KQP + 2 \frac{K(K-1)}{2} P - \displaystyle \sum _{i=0}^{K-1} ( a_iP + C_{a_i} )
 = sum +  KQP + K(K-1) P - \displaystyle \sum _{i=0}^{K-1} ( a_iP + C_{a_i} )
となり、これを最大化したいので、 a_0, a_1, … , a_{K-1}  iP + C_i が小さいものから  K 個選んでくるのが最適となる。

よって、 K を全探索してあげると良い。