• FF2のHP/MPを最大にしたい(FC)

    2019-03-02 23:09

    10年ほど前に「FF2の4人(フリオニール、マリア、ガイ、レオンハルト)のステータスを最大にしたい」と思ったが、HPとMPを65535にするのがすごく面倒なためにやらなかった。まずは以下の条件の下で必要な戦闘回数を算出する。

    • たいりょく/まりょくは途中で下がらない(実際には、たいりょくは下がりうるが、ひとまず考えない)
    • HPとたいりょく(MPとまりょく)は同時に上がる(うまくやると片方だけ上げられるらしいが、確認できていない)
    • HPが上昇してからたいりょくは上がる(MPとまりょくについても同じ)
    初期HP初期MP初期たいりょく初期まりょく
    フリオニール305105
    マリア20555
    ガイ405155
    レオンハルト109854632

    これらの初期ステータスより、例として、初期MPが5, 初期まりょくが5の場合に何回の戦闘でMPが65535になるか計算する。

    MP ≡ 初期MP + (まりょくが初期まりょくから99になるまでの和) + 99*k (mod 65536)
      ≡ 5 + (5 + 6 + ... + 99) + 99k (mod 65536)
      ≡ 4945 + 99k (mod 65536)
      ≡ 65535 (mod 65536)

    なので、 99k ≡ 60590 (mod 65536) となる最小のkを求めればよい。愚直にループでも回して求めると k=1274 (とその倍数)である。これに (5 + 6 + ... + 99) の項数を足すと、必要な最小の戦闘回数は 1274 + (99 - 5 + 1) = 1369回 である。

    この結果を見て、当時はあきらめた。時間がかかりすぎるから。
    他のキャラクターについて同様の計算をした結果は下の表に示す。

    HP[回]MP[回]
    フリオニール46741369
    マリア291721369
    ガイ212191369
    レオンハルト4435631136

    これはきつい。やってられない。

    たいりょく・まりょくのみ上げられる場合(確認できていません)

    この場合はもっと楽になる、例として、初期MPが5, 初期まりょくが5の場合に、何回の戦闘でMPが65535になるか計算する。

    初期MP + (まりょくが初期まりょくから99になるまでの和) + 99*k
    が 65535 以上になる最小のkについて、そのときのMPを m とおく。

    次に、 m - 65535 を計算し、その値を n とおく。

    n が分かったなら、たいりょく(まりょく)が n のときはたいりょく(まりょく)のみ上昇させる(HP/MPは上昇させない)。

    この場合の、戦闘回数とnの値は下の表に示す。

    HP(回、スキップするたいりょく)MP(回、スキップするまりょく)
    フリオニール703回, 87708回, 97
    マリア707回, 13708回, 97
    ガイ698回, 37708回, 97
    レオンハルト666回, 66685回, 7

    レオンハルトのMPについてはさらに調整が必要である(初期まりょくが32なので、『まりょくが7のときにMPを上げない』ことができない)。これについては、以下のようにする。

    1. 686回戦闘する。このときのMPは 65641 となる。
    2. 65641 - 65535 = 106 だから、2回の戦闘で合計106のMPを上げずにまりょくのみ上げる。
    3. 具体的には、例えば、まりょくが52と54のときはMPを上げずにまりょくのみ上げる。

    この計算が間違っていたら泣ける……


  • 広告
  • AtCoder解答用テンプレートこうしてます

    2018-07-29 21:51
    def c_modulo_summation(N, A):
        return sum(a-1 for a in A)

    import os
    import sys
    import io
    import pathlib
    import textwrap

    if os.name == 'nt':
        sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
        sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
        sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
    os.chdir(pathlib.Path(__file__).parent.resolve())

    for SAMPLE_CASE_NUM, INPUT in enumerate([
        """
        3
        3 4 6
        """,
        """
        5
        7 46 11 20 11
        """,
        """
        7
        994 518 941 851 647 2 581
        """
    ], 1):
        sys.stdin = io.StringIO(textwrap.dedent(INPUT).strip())
        N = int(input())
        A = [int(i) for i in input().split()]
        print(f'C-{SAMPLE_CASE_NUM}:{c_modulo_summation(N, A)}')

    上のコード (Python3.6以降で動作する) は、"AtCoder Beginner Contest 103" のC問題のサンプルケースに対する解を求めるためのものです。以下の点が特徴です。

    1. 解答を関数の中に書いている
    2. 関数の外で入力を受け付けている
    3. 入力を別ファイルに書いておかず、解答と同一ファイルに書いている

    こうしている理由は、個人的に次のような感覚を持っているからです。

    1. 「解が複数あるときはそのうち1つを出力すればよい」場合、解が1つ見つかればそれを即座に返り値にすればいい(解を出力してsys.exit()でもいいけど)
    2. 関数に渡す前に値のチェックをしておきたい(AtCoderでは見かけないので書いてはいないけれど、形式が違う入力や悪意のある入力を弾く必要があるため)
    3. サンプルの内容を確認するためにいちいち他のファイルを開きたくない

    このコードでは、日本語の入力があったときや日本語で出力を行うことを考えて標準入出力の文字コードをUTF-8にしたり、ファイルに書き込むことを考えてディレクトリを設定していたりしますが(if os.name == 'nt': のあたりの部分)、競技プログラミングで日本語の入力が与えられたり途中でファイルに書き込む必要があったりすることは今のところなかったので、不要だとは思います。

    2018/08/01 追記

    Windows 10 UTF-8利用機能が追加されていたようです
    ↑こちらのサイトのように、ワールドワイド言語サポートで Unicode UTF-8 を使用すると、ソースコード側で標準入出力のエンコーディングを設定しなくても日本語が文字化けすることがなくなりました。というわけで、 sys.std* = ... の部分は現在消してあります。

    2018/10/01 追記

    テンプレートをさらに変えました。内容は以下の通り。

    1. デコレータを使うようにした(入力を受け取って解を表示する部分も、コピペして提出欄にそのまま貼り付けれれるようになった。参考:Pythonのデコレータについて)
    2. import文の並びを変えた(VSCodeの "import 文を並び替える" の結果に従うようにした)
    def output_format(q):
        def decoration(func):
            def wrapper(*args, **kwargs):
                import time
                start = time.perf_counter()
                ans = func(*args, **kwargs)
                elapse = round((time.perf_counter() - start) * 1000, 3)
                res = f'{q}-{SAMPLE_CASE_NUM}: {ans} ({elapse}ms)'
                return res
            return wrapper
        return decoration


    @output_format('C')
    def c_modulo_summation(N, A):
        return sum(a - 1 for a in A)


    if __name__ == '__main__':
        import io
        import os
        import pathlib
        import sys
        import textwrap
        os.chdir(pathlib.Path(__file__).parent.resolve())

        for SAMPLE_CASE_NUM, INPUT in enumerate([
            """
            3
            3 4 6
            """,
            """
            5
            7 46 11 20 11
            """,
            """
            7
            994 518 941 851 647 2 581
            """
        ], 1):
            sys.stdin = io.StringIO(textwrap.dedent(INPUT).strip())
            N = int(input())
            A = [int(i) for i in input().split()]
            print(c_modulo_summation(N, A))
  • Visual Studio Code で"$"を打ち込むと"$$"で閉じてほしいとき

    2018-06-25 18:34

    VSCodeを使ってhtmlファイルを編集しているときに"$"を入力すると、"$$"と入力されたあと、2つの$の真ん中にキーが移動してほしい(カッコを入力したときと同じように)。

    なぜかというと、MathJaxを利用してLaTeXコマンドによって数式を記述しているのだけれど、インラインで数式を表示させたいときに"$$" or "\(\)" で数式を囲んでいるから。いちいちドルマーク2回打ち込んでその間に移動させるの面倒だし。

    というわけで、タイトルの内容を実現させるために調べた結果を書く。こうすればいいはず。

    1. */VSCode/resources/app/extentions/ (*はVSCodeをインストールした場所)の下にある"html"ディレクトリを ~/.vscode/extensions/ の下にコピー
    2. ~/.vscode/extensions/html/language-configuration.json を開き、"autoClosingPairs"に以下の内容を追加
      { "open": "$", "close": "$"}
    3. 文章を選択して"$"を入力したとき、選択した文章の前後に"$"を追加したい場合は、"surroundingPairs"に以下の内容を追加
      { "open": "$", "close": "$"}

    これで所望の結果が得られた。設定を.vscodeの方に移すことで、設定のエクスポートもやりやすくなると思う。

    別の文字で同じことをしたい場合も、上のやり方でできる。ただし、「"\("を入力すると"\)"で閉じる」ことは無理っぽい。1文字しか無理なのかな?