Cannon

有一个 的棋盘,第一行摆了 个炮,第二行摆了 个炮。

依次求发生 个炮吃炮事件的方案数。

有考虑两行之间的顺序和不考虑两行之间的顺序 两个子问题。

一行 个炮操作 次的方案是

,问题即求
$$

问题一直接递推,问题二维护一个组合数前缀和即可。

// Author:  HolyK
// Created: Tue Jul 20 21:51:46 2021
#include <bits/stdc++.h>
#define dbg(a...) fprintf(stderr, a)
template <class T, class U>
inline bool smin(T &x, const U &y) {
  return y < x ? x = y, 1 : 0;
}
template <class T, class U>
inline bool smax(T &x, const U &y) {
  return x < y ? x = y, 1 : 0;
}

using LL = long long;
using PII = std::pair<int, int>;
constexpr int P(1e9 + 9);
inline void inc(int &x, int y) {
  x += y;
  if (x >= P) x -= P;
}
int fpow(int x, int k = P - 2) {
  int r = 1;
  for (; k; k >>= 1, x = 1LL * x * x % P) {
    if (k & 1) r = 1LL * r * x % P;
  }
  return r;
}
constexpr int N(1e7 + 5);
int n, m, fac[N], ifac[N];
int bin(int n, int m) {
  return m >= 0 && m <= n ? 1LL * fac[n] * ifac[m] % P * ifac[n - m] % P : 0;
}
int main() {
  std::ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  std::cin >> n >> m;
  n -= 2, m -= 2;
  fac[0] = ifac[0] = 1;
  int k = n + m;
  for (int i = 1; i <= k; i++) fac[i] = 1LL * fac[i - 1] * i % P;
  ifac[k] = fpow(fac[k]);
  for (int i = k - 1; i; i--) ifac[i] = 1LL * ifac[i + 1] * (i + 1) % P;
  int ans = 1;
  for (int i = 1, x = 1; i <= k; i++) {
    x = 2LL * x * (k - i + 1) % P;
    ans ^= x;
  }
  std::cout << ans << " ";
  ans = 1;
  int s1 = 0, s2;
  for (int i = 0; i < n; i++) inc(s1, bin(k, i));
  inc(s2 = s1, bin(k, n));
  for (int i = 1, x = fpow(bin(k, n)); i <= k; i++) {
    s1 = (s1 - bin(k - i, n - i) + P) * (P + 1LL >> 1) % P;
    s2 = (s2 + bin(k - i, n)) * (P + 1LL >> 1) % P;
    x = 2LL * x * (k - i + 1) % P;
    ans ^= 1LL * x * (s2 - s1 + P) % P;
  }
  std::cout << ans << "\n";
  return 0;
}