https://yukicoder.me/problems/no/721

解法

余談

余談2

テスター当時はRuby版しか答案作ってませんでしたが解説のためにC版を急遽作りました。。

参加記というより反省会(あとで突っ込まれないように。。)

  • ポケモンGo、フリーザーを25体撃破しLv37にした。あづい。

コンテスト

時間 言語 問題(A-H) コメント
0:01 Ruby A AC 時間がかかったのはペナルティに気をつけるためです。
0:03 Ruby B AC
0:18 Ruby D 愚直な循環検出を書いたが、実行間に合わず。
0:29 C++ D C++に移植したがTLE 焦る。
0:46 Ruby C 下と右のマス数を掛け算。TLE (解説の方針と同じなんです)
1:12 Ruby/C++ D 申し訳ありません。C++の実行結果をzlib圧縮して埋め込みました。AC
1:17 Crystal C TLE
1:35 C++ C AC ところでvector transposeをライブラリとして持っていたから助かりましたが、持っていなかったらどうなっていたんでしょう。ぞっとします。
1:59 Ruby E コストテーブルを作って最短路という方針は思いつきましたが間に合いませんでした。heapqは以前私がAOJにてheapq.pyを移植したのをコピペしました。
(あとで確認したらRubyでは間に合わない感じでしたのでどうせ無駄でしたね…)
2:00 264位でした。さすがに雑魚すぎました…

ライブ

拝見しました。山内さんちょくだいさんお疲れ様でした。

E問題その後

言語 コメント
Ruby 遷移式が少し間違っていて、1 2 2 LU SGが1ではなく3になっていたorz
まあサンプルはそこまで強くなくても文句言えないけど…
Ruby 同じ行にSとGがあるときGを検出できていなかったorz
Crystal TLE
Python TLE
C++ AC

なんでCrystalだといかんのだ。。

まとめ

  • 実装遅いのを()
  • Crystalを–releaseでコンパイルしてほしい

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1155

構文解析とは何だったのか(2回目)

解法

  • Ternaryクラスを用意してevalに投げ込みます。

解答例

感想

  • 知識の証明の時点ではPythonが公式に使えるようになっていたので、下手な構文解析を出すと言語機能で突破されかねませんよって話。この問題は当時Pythonが使えなかったから許されたんだと思う。

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2883

構文解析とは何だったのか。

解法

  • 例として[+c[+a[^bd]]]O[c][O[a][X[b][d]]]に変換します。
  • O、A、Xはそれぞれ2引数を取りor、and、xorするProcで、カリー化されています。
  • 変換された文字列は正しいプログラムなので、evalでバッチリです^^

Python

  • Pythonはfunctools.partialはありますが演算子の形でカリー化することができないので、自前で関数をネストしてカリー化を行います。
  • なおPythonはRubyのProcで必要な特別扱いが必要ないので、括弧は丸括弧を使います。
  • (ところで答案内のtranslateのインポート方法に癖がありますが、Py2/3対応にするにはやむを得ないものです。)

解答例

https://yukicoder.me/problems/no/698

解法

  • bitDPを使うのが一般的な解法ですが、計算量が増えるものの、next_partial_permutationを使うこともできます。
  • 標準関数ではありませんが、next_permutation(v.begin(), v.end())する直前にreverse(v.begin()+middle, v.end())するだけなので、(next_combinationと違って)インラインで組み込むのは簡単です。
  • v.begin()からv.begin()+middleまでを(middle P sizeの)部分順列として使います。
  • ただし、ループが回るたびに、v.begin()+middleからv.end()まではソートされていることが保証されています。この性質を利用することで、vからsize-middle個選んでから残りのmiddle個を総当たりしたのと同じことになるのです。
  • ループ回数は14P7 = 17297280回です。

解答例

チームを作ろう2

https://abc096.contest.atcoder.jp/tasks/abc096_d

出力

  • AGC001以降のAtCoderでは、区切りは空白区切り改行区切りのどちらでも構いません(trailing spaceも可)。
  • よってputs arr*' 'puts arr、ひいてはp *arrでokです。以下では後者を使います。

解法

  • 5で割ってあまりが1になる整数の集合から5個選んだ合計は5で割り切れます。
  • 素数を列挙していき、1の位が1であるものをN個拾えば良いです。
    • 実際には1の位は(統一していれば)1,3,7,9のいずれも大丈夫です。以下の答案では9を採用しています。
    • 64bytes
1
require'prime';p *Prime.each(1499).select{|e|e%5>3}[0,gets.to_i]
  • 1の位がX(奇数、以下の答案では3)である整数を全て列挙し、素数をN個拾うようにすると以下のようになります。
  • 62bytes
1
require'prime';p *3.step(1499,5).select(&:prime?)[0,gets.to_i]

フェルマーテスト

  • require'prime'をカットすることで字数の節約にはなりますが、Integer#prime?は使えなくなるので、別の素数判定が必要になります。そこで、フェルマーテストを用います。
  • [1]に載っている式、2**i%i==2を使います。なおこの素数判定の場合stepの初期値を1にすることはできなくなるので注意してください(3,7,9は可)。
  • 51bytes
1
p *3.step(1499,5).select{|i|2**i%i==2}[0,gets.to_i]

redo

  • [2]では、ループカウンタをインクリメントしないよう、条件を満たさない場合はredoを使っています。これはPerlだけでなくRubyでも有用なテクニックです。
  • https://abc096.contest.atcoder.jp/submissions/2470406 (最終答案)
  • 46bytes
1
i=3;gets.to_i.times{i+=5;2**i%i==2?(p i):redo}

discussion

  • フェルマーテストやredoの実践例を挙げることができました。どちらもゴルフには有用であると思われます。

reference

  1. cojnaさん https://abc096.contest.atcoder.jp/submissions/2465874
  2. %20さん https://abc096.contest.atcoder.jp/submissions/2467541

https://bcu30-2018.contest.atcoder.jp/tasks/bcu30_2018_a

概要

(現状問題公開されてないですからね…)

1個ずつ数字が書かれた球がA個ある。これを1個ずつ数字が書かれたB個の球にしたい。ただし変換は以下の2種類。

  • 数xと数yが書かれた2個の球を数x * yが書かれた1個の球にする
  • 数xが書かれた1個の球を、(x%y==0となるような適当なyを選んで)数yと数x / yが書かれた2個の球にする

この条件で最終状態を達成できるか?AおよびBは9以下、書かれている数はそれぞれ100以下。

解法

  • 探索…は必要ないです。乗算と余りのない除算のみで構成されるということは、素因数です。素因数の組が等しい…つまり、状態Aの数の積と状態Bの数の積が等しければYesです。
  • 多分、制約は、積がint64に収まるようにってことなんだと思う。

感想

  • 気づきづらい。
  • 本当は「積が等しいかどうか判定せよ」という問題だったけど、がち勢が多かったので難しくしたらしい。
  • おかげで体感300点ぐらいでした…つらいよぅorz

概要

  • N(=3000)枚の寿司ネタ(a-zの26種類)を連続して流す(文字列Sとする)。
  • その中からM(=7)枚の部分列がQ(=30000)個問い合わせられる。ただし場合により部分列は連続していないことがある。
  • そのそれぞれに対し、S上でのインデックスを答える。

決定的アルゴリズム

この問題、D=1とすれば、部分列は連続であることが保証されます。つまり、決定的アルゴリズムを使うことができます。

  • N枚のうちで連続したM枚についてすべて異なるようにSを生成します。
    • 完全に決定的にするには https://en.wikipedia.org/wiki/De_Bruijn_sequence とか使うんですが、発展のために少しでもエントロピーを上げたいので、この部分は乱択を使って良いと思います。
  • すべて異なることがわかっているのだから、M枚の部分文字列を単にSから探すだけで終わりです。
  • Sの生成さえできれば、1ケースに付き30000点、 合計300000点を確実に獲得できます。

  • Rubyの事実上初版 https://rco-contest-2018-final-open.contest.atcoder.jp/submissions/2177816

発展

  • この状態であれば、0..Nのそれぞれ(j)に対し、qがS[j,M*3]中にこの順番で入っている数(ただしSの先頭に入っているほど重みを大きくする)が最大となるjをインデックスとして答える実装にすることで、D=2.5程度までは安定してインデックスを求めることができます。
    • 「*3」は、元となる部分文字列の長さはM*3以下であることを期待しています。
  • この「重み」が評価関数の肝になると思うのですが、調整の余地が残っている気がします。

  • C++の(コンテスト後)最終版(381792点) https://rco-contest-2018-final-open.contest.atcoder.jp/submissions/2179945

  • なお、コンテスト中は元となる部分文字列の長さがMであり、qの長さがM未満になりうると誤読していました、D=1.5にしかできなかったので324730点どまりでした。無念。

記事としての結論

  • 順位表で、ある点数を取っている人が沢山いる場合は決定的アルゴリズムを疑うのは有用ではないかと思います。

補足

  • Sの一例は次のとおりです:
1
kzsbqmuxtqwazgonugucjaouqsihsmgjpvdiwscfaewltvsyolgoenjcmlylyzhqlhgaypshugqlrqfxjigsliujfconzsyrnctoeztichmtznzxfhfkcpytpenkyqxmwxeaihahytbkbqkzxplhdtnzbsnpwhdpzjykrgwoxihvkiqrgmruztplaiuqecvbrvlbkwsbylxgxytyhsyiedtfvkjiylnjmcmhvtlkrmqbafrhngsqrvfbkadbkjshyhbagjoyhqmwipzegzqjkpxoquezkdplxombjqkdtbgnghkdaregkmrxelhpfbfoewbnfewmqvyivwkhfahoryxqvqnoguwpcldzcqlbpfruijrenfofeajcnrtcnqlzhbwdxwglmbkhdfhdyhfinxkwksypafghuoilqofnmbiavcqtjszdtowlqsdienoymvlrhczlysmlokhbvluaelotziotdtcwnvsigjnfjfywkeyalcmxgwyojkjrigvlnoqehmgopgvhntqxvnmxobebiwbzomjracdoerdndvbdygoyeayujwhtoiouxhmdbqusqbmqwnucgbzligimgnaswqbcdjchomvihdwmksltueulypyjsrnjeyoipdfxtveurkuwxatwmawmvrahsgexunjrdzemesmkfxmdzjvqxijdqoabvahbzeklborztczqlicyzbpemqinofcfuvaznakgxaevhcmqgmnescpxghixypxsxcxcqsqpkldvycwkxhkqcwqlqxnpoazsohnoucsztqdizbntfdeteiximtuymuzodlquigwhzoqjezyqahpkifvbyhkibmhslzdwybpojuegpyopwcdigpepmgpgdgdlumhrnfscleimrhriyjxfypdawcybayotfguipljmjvzxixpxugnlzvqemwluzwskegvpmpvrftyrfegxwetstcouotmofsakluqdmliroqiaodhrbvxnqgwrqntenstlhykhjalzlwuqvcmwawfyqojhpymlgycsxyhgqxjvesdbifgxitdikicrtnuzywysuvxrsidvtwisowtvltfyvmeqdpnzhklcvxmygjzmtpfqzezwkgiwfdctpchqfljqenqbxhxuivldilsldfesvtebuxcpqsharzikqnvxudumxqlknkpblcicqjimafnaqbocjmguzcliduealstwhnyqcbypexcnyjndbwgvefjwlbzilcqejkylrwqmbzsxolbvuihmkvyjlwkitvthxsmozyektmnhxifxziytweudfnhipwstdzwqcekmuswolxrvwagpfhlgwqhqsgocwioykxpnlkpcjtzdfwfxnfrdjnpkmfkninbsmpdblqveasiejnqxthdioxfpruxabcjftnkgdphravwvzlcgtonqcftlckmvmxvhojwuzpetwyhzvcrgclxembtiksgkxrnwhpamnrcztbftknzijgsrxwnfxrzhacvfakjapavrbrmdacqhurnqozroebwnqjgmcnpdwkrhzwbrusawknwyglczmewansanujgkljlntcbxeqtuczwnsvawpgkzkzqnruqbnuoepfxylqmqfodorsrlyuhoxtgxqizpzokjqskcapuoctghnhsprjgyayidqelwfaufxvpcqgtbvgltgbrbmtawovsdvsnmjymqdtkjeptmhmcjenmwktbnvmqnjyuceclnpeqktpdhclyvwbszlqlvzbahuktlwyzphaoaftshmvelbhvbqyfatbjmknybdnpjpxtovwodvxzdapgwbekptxputuqwsfrcqyauvegdfcjsjudqnqiqsfzeoevlkdczpkwejcfekodqdcpzqsjfhgkovcjzhtnyosceiknalxljzpcsnqnpvigrmblkflihbrireolvlpmyunynuemvfkmyhryqvwcqrbnryjydnsusbesncslszxjpirhqxbfnsxlwsrbxurvjystorpmeiyxcmgynknfdlzqgatiyhmyfksjbcokchpbgxgjkiafsmzepbfmjzyntzcalnfufqlgqkwynmizavocyqijpuevsjdlvbwmycvepjzvhxznxlyhaeypicgiyfnxwasyukgmiwikmgtkvgwevafmkpnphuvczrjcgqewivjugpikduiofvaeshowxzcuxecemurqieiflobzxbxswciepxwfmhkevjxtngfxgckfvtztjyznqkyiymeauyvkdgspmzgxmxuoztrkpudrdowrysdcozcpbydsygxroclwhldqrzswnldbgjybwhrseljwmclgzabgpmthltqocahrzrnowgpcrzkazcyhxqdknlapzhjyhjsnejbnoeabjvdcxjkgcniokyxyjujkfmtgrxdvwpnbxficmzrbspvozlsmdoxdefbhgmfumuakdxdivrvzjfdngjqxutjeibzahvmktqjvryplivblnetnvukxjmvtgzidxhokfhicoaqvhpmwpoefwgqsznyczfetgnfqtwornmnslycqodunanvrzvtufmxdqubnqfbyzrwcmyteukdskmjhsijkhzqopckiobdabsyzujbxjnymiaroiwafpwbpihqnhlmxsopoxbqrfxhavgqurfpkgskntoavqdbfhqkfyspwmihrtesoemfnbwswyqutsaujcdkepdukawaigywzveizimplsnvalkgrgeuznvbxgeruhwoijvmcazucrvofdmvuqcsyejrmeyclsgafckhcdtpvlvymcvswgfzkphxbmgcdxzlxzqmdwocowclvwrspkurzjsbnxfxiatubjfriasfyxwdejpmsfvmfptijwykizxoubgetmbsogpwqwkqlsfxklopxpwjwrpizgqonplrpfpmqagnmcgcoqgemovxtxrkdnwqugvmyqetbiqchfcmpsunwjnuplmzwjplfj