Page List

Search on the blog

ラベル Google Code Jam の投稿を表示しています。 すべての投稿を表示
ラベル Google Code Jam の投稿を表示しています。 すべての投稿を表示

2017年6月3日土曜日

Distributed Code Jam Round 1 2017 E. query_of_death

問題
GetValue(i)を呼ぶとi番目の値(0 or 1)が返ってくる。
ただし、あるiを使ってGetValue(i)を呼ぶとシステムが死んでしまう(他のノードに対しては影響はない)。以下ではこのiをi_qodと呼ぶ。
i = 1 〜 NまでのGetValue(i)の和を求めよ。

制約
N <= 10^8
ノード数: 100

解法
semiexp.さんの解法が綺麗。
まずノードをmasterとslaveに分ける。
masterは計算する範囲をslaveに渡す。slaveは与えられた部分問題をといてmasterに返却する。1回目のbatchで1つのslaveが死ぬが、i_qodを含む範囲が1/99に絞られる。続いて2回目のbatchでも1つのslaveが死ぬが、i_qodを含む範囲がさらに1/98に絞られる...というふうに分割統治的に解ける。見ればわかるけど、自分じゃ思いつかない。

ソースコード
// DCJ templates begin
template <typename T>
void PutStruct(int target, const T &v) {
  char *p = (char *) &v;
  for (int i = 0; i < sizeof(T); i++) {
    PutChar(target, p[i]);
  }
}

template <class T>
T GetStruct(int source) {
  char buf[sizeof(T)];
  for (int i = 0; i < sizeof(T); i++) {
    buf[i] = GetChar(source);
  }
  return *((T *)buf);
}
// DCJ templates end

int calc(pair<int, int> pr) {
  int l, r;
  tie(l, r) = pr;

  if (l == r) return 0;
  if (r - l == 1) return GetValue(l);

  int sum = 0;
  for (int i = l; i < r; i++)
    sum += GetValue(i);

  int ck = 0;
  for (int i = 0; i < 50; i++)
    ck += GetValue(l);

  if (ck != 0 && ck != 50)
    return -1;
  return sum;
}

int main() {
  int rank = MyNodeId();
  int NN = NumberOfNodes();
  
  if (!rank) {
    long long L = 0;
    long long R = GetLength();
    set<int> alive;
    int sum = 0;
    
    for (int i = 1; i < NN; i++)
      alive.insert(i);
    
    for (;;) {
      bool update = false;

      vector<int> vs(ALL(alive));
      for (int i = 0; i < vs.size(); i++) {
        int l = L + i * (R - L) / vs.size();
        int r = L + (i + 1) * (R - L) / vs.size();
        PutStruct(vs[i], make_pair(l, r));
        Send(vs[i]);
      }

      for (int i = 0; i < vs.size(); i++) {
        Receive(vs[i]);
        int s = GetInt(vs[i]);
        if (s == -1) {
          update = true;
          int l = L + i * (R - L) / vs.size();
          int r = L + (i + 1) * (R - L) / vs.size();
          L = l, R = r;
          PutStruct(vs[i], make_pair(-1, -1));
          Send(vs[i]);
          alive.erase(vs[i]);
        } else {
          sum += s;
        }
      }
      if (!update)
        break;
    }
    
    for (auto &x : alive) {
      PutStruct(x, make_pair(-1, -1));
      Send(x);
    }
    
    cout << sum << endl;
  } else {
    for (;;) {
      Receive(0);
      auto pr = GetStruct<pair<int, int> >(0);
      if (pr.first == -1)
        break;
      int s = calc(pr);
      PutInt(0, s);
      Send(0);
    }
  }

  return 0;
}

2017年4月9日日曜日

Google Code Jam Qualification Round 2017

 Code Jam 2017の予選があった。ABCの3問を解いて、通過ラインを超えることができた。Dの問題を復習しておく。

問題
Fashion Show

考察
  • 各モデル達はチェスのルーク、ビショップ、クイーンのどれかに対応する
  • 8クイーン問題的に考えることができる
  • ビショップとルークの問題を独立して考えることができる
  • クイーンのポイントは2点なので、ビショップとルークの問題を解いてそのままマージすればOK
  • 各配置問題は(行, 列)または(左斜め軸、右斜め軸)の二部グラフのマッチングをすればOK

ソースコード

using namespace std;

#define ALL(x) (x).begin(), (x).end()
#define EACH(itr,c) for(__typeof((c).begin()) itr=(c).begin(); itr!=(c).end(); itr++)  
#define FOR(i,b,e) for (int i=(int)(b); i<(int)(e); i++)
#define MP(x,y) make_pair(x,y)
#define REP(i,n) for(int i=0; i<(int)(n); i++)

int n;
int m;
int bd[100][100];
int be[100][100];

class BipartiteMatching {
  int V;
  vector<vector<int> >G;
  vector<int> match;
  vector<bool> used;
  
  bool dfs(int v) {
    used[v] = true;
    for (int i = 0; i < (int)G[v].size(); i++) {
      int u = G[v][i];
      int w = match[u];
      if (w < 0 || (!used[w] && dfs(w))) {
        match[v] = u;
        match[u] = v;
        return true;
      }
    }
    return false;
  }
  
public:
  BipartiteMatching(int v_size) : V(v_size), G(V), match(V), used(V) {}
  
  void add_edge(int u, int v) {
    G[u].push_back(v);
    G[v].push_back(u);
  }
  
  int count() {
    int ret = 0;
    fill(match.begin(), match.end(), -1);
    for (int v = 0; v < V; v++) {
      if (match[v] < 0) {
        fill(used.begin(), used.end(), false);
        if (dfs(v))
          ++ret;
      }
    }
    return ret;
  }

  int getPair(int v) {
    return match[v];
  }
};

void solve() {
  cin >> n >> m;
  memset(bd, 0, sizeof(bd));
  REP (i, m) {
    char t;
    int y, x;
    cin >> t >> y >> x;
    --x, --y;
    if (t == 'x') bd[y][x] = 1;
    else if (t == '+') bd[y][x] = 2;
    else if (t == 'o') bd[y][x] = 3;
  }

  REP (i, n) REP (j, n) be[i][j] = bd[i][j];

  // rook
  BipartiteMatching rook(2 * n);
  set<int> used;
  REP (i, n) REP (j, n) if (bd[i][j] & 1) {
    used.insert(i);
    used.insert(j + n);
  }
  REP (i, n) REP (j, n) if (!used.count(i) && !used.count(j+n)) rook.add_edge(i, j+n);
  rook.count();
  REP (i, n) {
    int j  = rook.getPair(i);
    if (j != -1) {
      be[i][j-n] |= 1;
    }
  }
  
  // bishop
  BipartiteMatching bishop(4*n);
  used.clear();
  REP (i, n) REP (j, n) if (bd[i][j] & 2) {
    used.insert(n-1+i-j);
    used.insert(2*n-1+i+j);
  }
  REP (i, n) REP (j, n) {
    if (!used.count(n-1+i-j) && !used.count(2*n-1+i+j))
      bishop.add_edge(n-1+i-j, 2*n-1+i+j); 
  }
  bishop.count();
  REP (i, n) REP (j, n) {
    int d1 = n-1+i-j;
    int d2 = 2*n-1+i+j;
    if (bishop.getPair(d1) == d2)
      be[i][j] |= 2;
  }

  // output score
  int score = 0;
  REP (i, n) REP (j, n) {
    if (be[i][j] & 1) ++score;
    if (be[i][j] & 2) ++score;
  }
  cout << score << " ";

  // output changed arrangement
  int cnt = 0;
  REP (i, n) REP (j, n) cnt += bd[i][j] != be[i][j];
  cout << cnt << endl;

  REP (i, n) REP (j, n) {
    if (be[i][j] != bd[i][j]) {
      char t = be[i][j] == 3 ? 'o' : (be[i][j] == 1 ? 'x' : '+');
      cout << t << " " << i+1 << " " << j+1 << endl;
    }
  }
}

int main() {
    ios_base::sync_with_stdio(0);
    int T;
    cin >> T;
    REP (i, T) {
        cerr << "Case #" << i+1 << ": " << endl;
        cout << "Case #" << i+1 << ": ";
        solve();
    }

    return 0;
}

2016年5月8日日曜日

Google Code Jam 2016 Round 1C Fashion Police

問題概要
あなたはJ枚のジャケット、P枚のパンツ、S枚のシャツを持っている。(J <= P <= S)

以下の条件を満たすように、毎日服装を選ばなければならない。
同じ{ジャケット、パンツ、シャツ}の組み合わせを2回以上着ることはできない。
同じ{ジャケット、パンツ}の組み合わせをK回以上着ることはできない。
同じ{パンツ、シャツ}の組み合わせをK回以上着ることはできない。
同じ{シャツ、ジャケット}の組み合わせをK回以上着ることはできない。

最大で何日間上記の条件を満たしながら服装を選ぶことができるか?
日数と服装の選び方を出力せよ。

解法
K >= Sの場合は、J*P*Sのすべてのパターンを1回ずつ着ることができる。
以下では、K < Sの場合を考える。

鳩ノ巣原理により、求める日数をxとすると、
x <= J * P * K
x <= P * S * K
x <= S * J * K
が成り立つ。さらに、J <= P <= Sの条件から、
x <= J * P * K
となる。

もし、x = J * P * Kとなるような選び方ができれば、それが解となる。
ジャケットをi, パンツをjに固定したとき、シャツkを以下のように選んでみる。
k = (i + j + d) % S, 0 <= d < K.

K < Sより、上のkはすべて異なっている。
このとき、固定した{ジャケット、パンツ}ごとにK通りのパターンがあるので、全体でJ * P * Kパターンの選び方ができていることに注意。

この選び方が{ジャケット、シャツ}および{パンツ、シャツ}を固定したときにも制約に違反していないことが確認できれば、これが解となる。

ジャケットをi, シャツをkに固定した場合を考えてみる。
(i, j, k)が解に含まれるとき、
k = (i + j + d) % S, 0 <= d < K.
となるようなdが存在する。このとき
j = (k - i - d) % S.
となる。dはKパターンしかないため、同じ{ジャケット、シャツ}のパターンがK回以上着られることはない。

{パンツ、シャツ}を固定した場合も同様にK回以上着られることはない。
よってこれが解となる。

実装
using namespace std;

#define ALL(x) (x).begin(), (x).end()
#define EACH(itr,c) for(__typeof((c).begin()) itr=(c).begin(); itr!=(c).end(); itr++)  
#define FOR(i,b,e) for (int i=(int)(b); i<(int)(e); i++)
#define MP(x,y) make_pair(x,y)
#define REP(i,n) for(int i=0; i<(int)(n); i++)

int J,P,S,K;

void solve() {
  cin >> J >> P >> S >> K;

  if (K >= S) {
    cout << J*P*S << endl;
    REP (x, J) REP (y, P) REP (z, S) {
      cout << x+1 << " " << y+1 << " " << z+1 << endl;
    }
  } else {
    cout << J*P*K << endl;
    REP (x, J) REP (y, P) REP (z, K) {
      cout << x+1 << " " << y+1 << " " << (x+y+z)%S+1 << endl;
    }
  }
}

int main() {
    ios_base::sync_with_stdio(0);
    int T;
    cin >> T;
    REP (i, T) {
        cerr << "Case #" << i+1 << ": " << endl;
        cout << "Case #" << i+1 << ": ";
        solve();
    }
    return 0;
}

2016年5月1日日曜日

Google Code Jam 2016 Round 1B

Round 1Bに参加した。
結果は、oooxoxで見事Round 1Cへの出場権を獲得した。
とりあえず復習したので、ソースをはっておく。

A. Getting the Digits
0-9の数字をアルファベットで書いたときに、Zは"ZERO"にしか出てこない。
よってZの数を数えれば、0の数がわかる。
0は消えたので、1-9のアルファベット表記を考える。Xは"SIX"にしか出てこない。
よってXの数を数えれば、6の数がわかる。
6は消えたので{1,2,3,4,5,7,8,9}のアルファベット表記を考える。Wは"TWO"にしか出てこない。よってWの数を数えれば、2の数がわかる。
....
という方針で解く。

using namespace std;

#define ALL(x) (x).begin(), (x).end()
#define EACH(itr,c) for(__typeof((c).begin()) itr=(c).begin(); itr!=(c).end(); itr++)  
#define FOR(i,b,e) for (int i=(int)(b); i<(int)(e); i++)
#define MP(x,y) make_pair(x,y)
#define REP(i,n) for(int i=0; i<(int)(n); i++)

int freq[128];
int cnt[10];
tuple<string, char, int> vs[] = {
  {"ZERO", 'Z', 0}, 
  {"SIX", 'X', 6},
  {"TWO", 'W', 2},
  {"FOUR", 'U', 4},
  {"THREE", 'R', 3},
  {"FIVE", 'F', 5},
  {"ONE", 'O', 1},
  {"SEVEN", 'S', 7},
  {"EIGHT", 'T', 8},
  {"NINE", 'I', 9}
};

void solve() {
  string s;
  cin >> s;
  memset(freq, 0, sizeof(freq));
  memset(cnt, 0, sizeof(cnt));

  for (auto &c: s)
    freq[c]++;

  for (auto &v : vs) {
    string x;
    char y;
    int z;
    tie(x,y,z) = v;

    cnt[z] = freq[y];
    for (auto &c: x)
      freq[c] -= cnt[z];
  }

  for (int i = 0; i < 10; i++)
    for (int j = 0; j < cnt[i]; j++)
      cout << i;
  cout << endl;
}

int main() {
    ios_base::sync_with_stdio(0);
    int T;
    cin >> T;
    REP (i, T) {
        cerr << "Case #" << i+1 << ": " << endl;
        cout << "Case #" << i+1 << ": ";
        solve();
    }

    return 0;
}

B. Close Match
2つの数をA, Bとする。Aの桁数をnとする。
A > Bが確定ならば、Aの後続の?は0で埋め、Bの?は9で埋めればよい。
A < Bが確定ならば、Aの後続の?は9で 埋め、Bの?は0で埋めればよい。

k桁目の値(k=0,1,...,nでループ)が決まると、はじめて上記のいずれかが確定するとする。
すると、i < kまではA[i]とB[i]は完全一致でなければならない。
k桁目の値は全列挙。
k+1桁目以降は、0、または、9で埋めればよい。

using namespace std;

#define ALL(x) (x).begin(), (x).end()
#define EACH(itr,c) for(__typeof((c).begin()) itr=(c).begin(); itr!=(c).end(); itr++)  
#define FOR(i,b,e) for (int i=(int)(b); i<(int)(e); i++)
#define MP(x,y) make_pair(x,y)
#define REP(i,n) for(int i=0; i<(int)(n); i++)

const long long oo = 1LL<<60;
long long diff;
string A, B;
string ra, rb;

void update(const string &a, const string &b) {
  long long d = abs(stoll(a) - stoll(b));
  if (make_tuple(d, a, b) < make_tuple(diff, ra, rb)) {
    diff = d;
    ra = a;
    rb = b;
  }
}

void doit(int k, int p, int q, int r, int s) {
  string a = A;
  string b = B;
  int n = A.size();
  REP (i, k) {
    if (a[i] == '?' && b[i] == '?')
      a[i] = b[i] = '0';
    else if (a[i] == '?')
      a[i] = b[i];
    else if (b[i] == '?')
      b[i] = a[i];
  }
  if (k < n && a[k] == '?') a[k] = '0' + p;
  if (k < n && b[k] == '?') b[k] = '0' + q;
  FOR (i, k, n) {
    if (a[i] == '?') a[i] = r ? '9' : '0';
    if (b[i] == '?') b[i] = s ? '9' : '0';
  }
  update(a, b);
}

void solve() {
  cin >> A >> B;
  diff = oo;
  int n = B.length();

  REP (k, n+1) REP (p, 10) REP (q, 10) REP (r, 2) REP (s, 2) {
    doit(k, p, q, r, s);
  }
  
  cout << ra << " " << rb << endl;
}

int main() {
    ios_base::sync_with_stdio(0);
    int T;
    cin >> T;
    REP (i, T) {
        cerr << "Case #" << i+1 << ": " << endl;
        cout << "Case #" << i+1 << ": ";
        solve();
    }

    return 0;
}

C. Technobabble
第一ワードと第二ワードをノードと考えてグラフを構築する。
第一ワードvと第二ワードwがtopicを構成するとき、枝(v, w)をはる。
すると、このグラフは二部グラフになることがわかる。

ある枝集合を選ぶと、すべてのノードが少なくとも1つの枝によってリンクされる
<=>
使わなかった枝はfakeとなる

と考えることができる。fakeの最大値が欲しいので、上記の条件を満たす最小の枝集合を選べばいい。これは最小辺カバーであり、

|最小辺カバー| = ノード数 - |最大マッチング|

という関係から、最大マッチングを求めれば計算できる。
using namespace std;

#define ALL(x) (x).begin(), (x).end()
#define EACH(itr,c) for(__typeof((c).begin()) itr=(c).begin(); itr!=(c).end(); itr++)  
#define FOR(i,b,e) for (int i=(int)(b); i<(int)(e); i++)
#define MP(x,y) make_pair(x,y)
#define REP(i,n) for(int i=0; i<(int)(n); i++)

class BipartiteMatching {
  int V;
  vector<vector<int> >G;
  vector<int> match;
  vector<bool> used;
  
  bool dfs(int v) {
    used[v] = true;
    for (int i = 0; i < (int)G[v].size(); i++) {
      int u = G[v][i];
      int w = match[u];
      if (w < 0 || (!used[w] && dfs(w))) {
        match[v] = u;
        match[u] = v;
        return true;
      }
    }
    return false;
  }
  
 public:
  BipartiteMatching(int v_size) : V(v_size), G(V), match(V), used(V) {}
  
  void add_edge(int u, int v) {
    G[u].push_back(v);
    G[v].push_back(u);
  }
  
  int count() {
    int ret = 0;
    fill(match.begin(), match.end(), -1);
    for (int v = 0; v < V; v++) {
      if (match[v] < 0) {
        fill(used.begin(), used.end(), false);
        if (dfs(v))
          ++ret;
      }
    }
    return ret;
  }
};


int n;
string a[1000], b[1000];

map<string, int> s2id(string s[], int n) {
  map<string, int> ret;
  REP (i, n) {
    if (!ret.count(s[i])) {
      int l = ret.size();
      ret[s[i]] = l;
    }
  }
  return ret;
}

void solve() {
  cin >> n;
  REP (i, n) cin >> a[i] >> b[i];
  auto aid = s2id(a, n);
  auto bid = s2id(b, n);

  int an = aid.size();
  int bn = bid.size();

  BipartiteMatching bm(an + bn);
  REP (i, n) bm.add_edge(aid[a[i]], an + bid[b[i]]);
  int edge_cover = an + bn - bm.count();
  cout << n - edge_cover << endl;
}

int main() {
    ios_base::sync_with_stdio(0);
    int T;
    cin >> T;
    REP (i, T) {
        cerr << "Case #" << i+1 << ": " << endl;
        cout << "Case #" << i+1 << ": ";
        solve();
    }

    return 0;
}

2014年6月22日日曜日

Google Code Jam 2014


 巷では「誰が一番上手にボールを蹴って枠に入れることが出来るか」を競う世界大会が話題になっているようです。プログラマーたちの間では「誰が一番正確にかつ高速に問題を解くアルゴリズムを考え、それを正確に実装出来るか」を競う世界大会が話題になっています。まあ、僕は早々と敗退したのでワールドカップ見てますが。

 とりあえず今年のCode Jamを振り返ってみます。

結果
去年は1バイトの違いでRound 3行きを逃してしまいました。
今年は現実的に"TシャツをGETする"を目標にして参加しました。結果は、惜しくも届かず。
Qualification Round 2,067 out of 25,462
Round 1A N/A
Round 1B 1,959 out of 7,381
Round 1C 875 out of 4,309
Round 2 1,005 out of 2,526

面白かった問題
Round 2までで個人的に面白かった問題。
  1. Don't Break The Nile
  2. Trie Sharding
  3. Enclosure
  4. Proper Shuffle
特に、Don't Break The Nileは印象的でした。最小カットを求めることで、最大フローを求めるという問題です。
最大フローから最小カットを求めるという問題はよく見ますが、その逆のパターンで、柔軟な発想力が求められる問題でした。

来年に向けて
去年まではたくさん問題を解くことに力を入れていましたが、今年からは良問を繰り返し解くというやり方にスイッチしました。
来年のCode Jamの結果を見てこの練習方針が効率的なのか否かを見極めようと思います。

2014年5月5日月曜日

Google Code Jam 2014 Round1B New Lottery Game

問題
A, B, Kが与えられる。以下の条件を満たす非負整数(x, y)の組み合わせ数を求めよ。
  • x < A
  • y < B
  • (x & y) < K
ただし、
 1 <= A <= 10^9,
 1 <= B <= 10^9,
 1 <= K <= 10^9.

解法
rng..58さんの解法(LSBを固定して再帰)がとても綺麗で分かりやすかった。こんなにシンプルに書けるのかという感じ。

正答者の多くはビット単位のDPで解いているようだった。何を状態数としてDPしているのか分からなかったのでじっくりと考えてみた。

簡単のため以下のような問題を考える。

正の正数Aが与えられる。x < Aを満たす非負整数xはいくつあるか?

答えはA個なのですが、この問題をわざわざビット単位で処理して解くことを考えてみます。

#include <iostream>

using namespace std;

int main() {
    long long A;
    cin >> A;

    int a[32] = {};
    for (int i = 0; i < 32; i++)
        a[32-1-i] = A >> i & 1;

    for (int i = 0; i < 32; i++)
        cout << a[i] << " ";
    cout << endl;

    int dp[32+1][2] = {};    // dp[bit][LSBs are arbitrary or not?]
    dp[0][0] = 1;

    for (int k = 0; k < 32; k++) {             // k  : bit (notice that we process from MSB to LSB)
        for (int i = 0; i < 2; i++) {              // i  : the next bit is arbitrary or not?
            int jt = i == 1 ? 1 : a[k];            // jt : the maximum next bit
            for (int j = 0; j <= jt; j++) {        // j  : next bit
                dp[k+1][i | a[k] > j] += dp[k][i];
            }
        }
    }

    cout << dp[32][1] << endl;   // how many non-negative integers less than A are there?
                                                   // "less than" means "not used up to A" -> LSBs are arbitrary.
    return 0;
}
MSBからLSBの方向に処理していきます。
状態数を(現在の桁, 次の桁以降を任意の値に出来るか?)とするのがポイントです。

ビットkからビット(k+1)への遷移を考えます。

もし、ビットkの時点で次の桁以降を任意に決められるのであれば、x[k+1]のビットは{0, 1}のどちらでも選べます。もし、ビットkの時点で次の桁以降を任意に決められないのであれば、x[k+1]のビットは、a[k+1]の値まで選べます。このx[k+1]のビットの最大値が上のソースコードのjtです。

jtが決まると、[0, jt]まででループを回して、x[k+1]のビットの値を決めます。
もし、ビットkの時点で次の桁以降の値を任意に決められるのであれば、k+1以降も同様に次の桁以降の値を任意に決めることが出来ます。
ビットkの時点で次の桁以降の値を任意に決められない場合は、
a[k+1] = 1、かつ、x[k+1] = 0
とした場合に次の桁以降の値を任意に決められることになります。
上のソースコードの dp[k+1][i | a[k] > j] += dp[k][i]; の部分がそれに対応します。

base caseは、dp[0][0] = 1とします。次の桁は任意に決められないので2つ目の添字は0です。
問題の解は、dp[32][1]になります。これはx < Aなので、ぎりぎり目一杯Aに寄っておらずもし次のビットが存在していれば、任意に決められるという意味で2つ目の添字は1にします。ちなみにdp[32][0] = 1です。これはa[k] = 1となるビットすべてでx[k] = 1としたことを意味しています。

状態数の取り方が特殊で難しいですが、おもしろいパターンのDPです。ここまで分かれば、元々の問題はこれの応用で解けます。

using namespace std;

#define ALL(x) (x).begin(), (x).end()
#define EACH(itr,c) for(__typeof((c).begin()) itr=(c).begin(); itr!=(c).end(); itr++)  
#define FOR(i,b,e) for (int i=(int)(b); i<(int)(e); i++)
#define MP(x,y) make_pair(x,y)
#define REP(i,n) for(int i=0; i<(int)(n); i++)

void solve() {
    int A, B, K;
    cin >> A >> B >> K;

    int ar[32], br[32], kr[32];  // bit expression: ar[0] = MSB, ar[31] = LSB

    for (int i = 0; i < 32; i++) {
        ar[31-i] = A >> i & 1;
        br[31-i] = B >> i & 1;
        kr[31-i] = K >> i & 1;
    }

    long long dp[32+1][2][2][2] = {};
    dp[0][0][0][0] = 1;
    
    for (int d = 0; d < 32; d++) {
        for (int i = 0; i < 2; i++) {           // next ar bit is arbitrary?
            for (int j = 0; j < 2; j++) {       // next br bit is arbitrary?
                for (int k = 0; k < 2; k++) {   // next kr bit is arbitrary?
                    if (dp[d][i][j][k] == 0)
                        continue;

                    int at = i == 1 ? 1 : ar[d];
                    int bt = j == 1 ? 1 : br[d];

                    for (int a = 0; a <= at; a++) {      // next ar bit
                        for (int b = 0; b <= bt; b++) {  // next br bit
                            int kk = a & b;              // next kk bit
                            if (k == 0 && kk > kr[d])
                                continue;

                            dp[d+1][i | ar[d] > a][j | br[d] > b][k | kr[d] > kk] += dp[d][i][j][k];
                        }
                    }
                }
            }
        }
    }
    
    cout << dp[32][1][1][1] << endl;
}

int main() {
    ios_base::sync_with_stdio(0);
    
    int T;
    cin >> T;
    REP (i, T) {
        cerr << "Case #" << i+1 << ": " << endl;
        cout << "Case #" << i+1 << ": ";
        solve();
    }

    return 0;
}