$B$ 個のノードの $1$ 番をスタート、$B$ 番をゴールとしたとき、
有向辺を辿るときのパターン数が $M$ 通りになるようなグラフを構築してください。
ただし多重辺は認められないものとします。
・$1 \le$ クエリの数 $\le 100$
・$1 \le B \le 50$
・$1 \le M \le 10^{18}$
以下 0-indexed です。
サンプルケースから、IMPOSSIBLE になるのはどんなときだろうと気になってくる。
そこで、辺を張れるだけ張ってみる。
閉路があったらその部分を何周かすればパターン数を無限に稼げるので、閉路は無いんだなというのは分かる。
辺を張れるだけ張ると左図のようになり、パターン数は
0-> 4 # 最後は 0 から 4
0-> 3-> 4 # 最後は 3 から 4
0-> 2-> 4 # 最後は 2 から 4
0-> 2-> 3-> 4 # 最後は 3 から 4
0-> 1-> 4 # 最後は 1 から 4
0-> 1-> 2-> 4 # 最後は 2 から 4
0-> 1-> 3-> 4 # 最後は 3 から 4
0-> 1-> 2-> 3-> 4 # 最後は 3 から 4
以上 $8$ 通りになる。
上記の内容を考察すると、
・パターン数の上限は、スタートとゴール以外のノード(中継地点と呼ぶことにする)に行くか行かないかで $2^{B-2}$ であること
・中継地点からゴールに行く最後の辺のパターン数は、$2$ の冪乗と規則的であること
が分かる(左図参照)。
パターン数 $M$ は $1$ 以上なのでスタートからゴールへの直接のルートは必ずあるようにし、
残りの $M-1$ パターンは中継地点から直接ゴールに行く辺を張るか張らないかで対応すれば答えになる。
スタートから各中継地点に行く第一歩めのパターン数で考えても良い。
#!/usr/bin/python2
# -*- coding: utf-8 -*-
# †
def f(B, M):
relay = B - 2 # スタートとゴール以外のノード数
if M > 2 ** relay:
return None
G = [[int(i < j) for j in range(B)] for i in range(B)] # G[B][B]
for i in xrange(relay): # M-1 の右から i 番目のビットが、i+1 番のノードからゴールへの辺の有無になる
G[i+1][B-1] = (M-1)>>i & 1
return '\n'.join(''.join(map(str, row)) for row in G)
T = int(raw_input())
for case in xrange(T):
line = raw_input()
B, M = map(int, line.split())
G = f(B, M)
if G:
print 'Case #{}: POSSIBLE'.format(case+1)
print G
else:
print 'Case #{}: IMPOSSIBLE'.format(case+1)
---
補題
逆に、グラフが与えられたときにパターン数を求めてください。
・$1 \le B \le 50$
・ノード $u, v$ において、$u \ge v$ なら $u$ から $v$ への有向辺は無いことが保証される。
サンプルケース
入力:
1
10
0111000100
0000010111
0000100101
0000101111
0000011111
0000001000
0000000100
0000000000
0000000001
0000000000
出力:
9
※テストデータの一行目はテスト件数です。
テストデータはこちら。
// †
#include <iostream>
#include <algorithm>
using namespace std;
using i64 = long long;
int B;
vector<i64> dp;
vector<string> G;
// iからゴールへのパターン数
i64 rec(int i) {
i64 &res = dp[i];
if(res != -1) { return res; }
if(i == B-1) { return res = 1; }
res = 0;
for(int j=i+1; j<B; ++j) {
if(G[i][j] == '1') { res += rec(j); }
}
return res;
}
int main(void) {
int T; scanf("%d", &T);
for(int loop=0; loop<T; ++loop) {
scanf("%d", &B);
G.resize(B);
for(int i=0; i<B; ++i) {
cin >> G[i];
}
dp.assign(B, -1);
i64 res = rec(0);
printf("%lld\n", res);
}
return 0;
}
(ΦωΦ)<
つづく