trsing’s diary

勉強、読んだ本、仕事で調べたこととかのメモ。

D - All Your Paths are Different Lengthメモ

問題

f:id:trsing:20200715212054p:plain D - All Your Paths are Different Lengths

考えたこと

なんかbit的な考え方?という臭いがしたのでとりあえず2^{N-1}\leq L \lt 2^{N}とおき、辺の長さを2^{i}としていい感じの有効グラフを構築してみます。

f:id:trsing:20200715212236p:plain
いい感じの有向グラフ

頂点1,N間に長さ0,\cdots,2^{N-1}-1のパスができあがっているので 残りの長さ2^{N-1},\cdots, L-1のパスを重複しないように作れないか考えます。

まずは直近の2^{N-1}の辺をどっかの頂点kから頂点Nに生やしてみます。

f:id:trsing:20200715212347p:plain

頂点kへのパス長は0,\cdots,2^{k-1}-1ですのでこいつに生やすと頂点1から頂点Nに長さ2^{N-1}, \cdots,2^{N-1}+ 2^{k-1}-1のパスが出来上がります。

頂点kの選び方ですが、 なるべく多くのパスをカバーしたいので 頂点N-1から逆に見ていくとよさそうです。 パス長がL以上になるならパスして次の頂点N-2を検討。

頂点kに辺を生やすと残りのパス長は2^{N-1}+ 2^{k-1},\cdots ,L-1となります。 次は2^{N-1}+2^{k-1}の辺を生やします。またk-1から見てやって L以上にならないものを選ぶ。 と繰り返していけばよさそうです。

これで本当にうまくいでしょうか?このやり方だと重複しないようにパスを作れるので、 0, \cdots, 2^{N-1}-1個の範囲でパスを任意に増やすことができればオッケーです。

頂点kに生やすと2^{k-1}個パス長が増えます。 N以外の頂点に生やせば最大で \sum_{k=1}^{N-1} 2^{k-1}=2^{N-1}-1個のパスを増やすことができます。 好きな2^{i}を選べますのでこの範囲で任意の数のパス長を増やせます。

コード

static void Solve()
{
    var L = Sarray()[0];
    var N = 0;
    for (var i = 0; i < 20; ++i)
        if ((L & (1 << i)) != 0) N = i;
    var graph = Enumerable.Range(0, N).Select(_ => new List<(int to, int c)>()).ToArray();
    for (var i = 0; i < N; ++i)
    {
        graph[i].Add((i + 1, 0));
        graph[i].Add((i + 1, (int)Pow(2, i)));
    }
    var last = L - 1;
    var now = (int)Pow(2, N);
    var pos = N - 1;
    while (now <= last)
    {
        var left = (int)Pow(2, pos) - 1;
        if (now + left <= last)
        {
            graph[pos].Add((N, now));
            now += left + 1;
        }
        --pos;
    }
    var m = graph.Sum(g => g.Count);
    WriteLine($"{N + 1} {m}");
    for (var i = 0; i < N; ++i)
    {
        foreach (var tc in graph[i])
        {
            WriteLine($"{i + 1} {tc.to + 1} {tc.c}");
        }
    }
}

Submission #15199902 - AtCoder Beginner Contest 108

背景

パスを追加していくところの理解に時間がかかったのでメモ