제출 #220243

#제출 시각아이디문제언어결과실행 시간메모리
220243rama_pangTents (JOI18_tents)C++14
100 / 100
239 ms35712 KiB
#include <bits/stdc++.h>
using namespace std;

const int MOD = 1e9 + 7;
const int INV2 = (MOD + 1) / 2; // modular inverse of 2

int ADD() { return 0; }
int MUL() { return 1; }

template<typename... Tail>
int ADD(int Head, Tail... T) {
  return (Head += ADD(T...)) >= MOD ? Head - MOD : Head;
}

template<typename... Tail>
int MUL(int Head, Tail... T) {
  return 1ll * Head * MUL(T...) % MOD;
}

template<typename... Tail>
void RADD(int &Head, Tail... T) {
  Head = ADD(Head, T...);
}

int PartialSolutionDP(int N, int M) { // solution in O(N^3)
  vector<vector<int>> dp, nxt_dp;
  dp = nxt_dp = vector<vector<int>>(M + 2, vector<int>(M + 2, 0)); // [free_column][unmatched_tent]
  dp[M][0] = 1;

  for (int row = 0; row < N; row++) {
    for (int free_column = 0; free_column <= M; free_column++) {
      for (int unmatched_tent = 0; unmatched_tent <= M; unmatched_tent++) {
        int cur = dp[free_column][unmatched_tent];

        // place 2 tents
        if (free_column >= 2) {
          RADD(nxt_dp[free_column - 2][unmatched_tent], MUL(free_column, free_column - 1, cur, INV2));
        }

        // place 1 tent by itself
        if (free_column >= 1) {
          RADD(nxt_dp[free_column - 1][unmatched_tent + 1], MUL(free_column, cur));
        }

        // place 1 tent adjacent to an unmatched tent
        if (unmatched_tent >= 1) {
          RADD(nxt_dp[free_column][unmatched_tent - 1], MUL(unmatched_tent, cur));
        }

        // place no tents
        RADD(nxt_dp[free_column][unmatched_tent], cur);
      }
    }

    swap(dp, nxt_dp);
    nxt_dp = vector<vector<int>>(M + 1, vector<int>(M + 1, 0));
  }

  vector<int> POW4(M + 1);
  POW4[0] = 1;
  for (int i = 1; i <= M; i++) {
    POW4[i] = MUL(POW4[i - 1], 4);
  }

  int res = 0;
  for (int free_column = 0; free_column <= M; free_column++) {
    for (int unmatched_tent = 0; unmatched_tent <= M; unmatched_tent++) {
      RADD(res, MUL(POW4[unmatched_tent], dp[free_column][unmatched_tent])); // each unmatched tent can be placd in 4 directions
    }
  }

  return (res - 1 + MOD) % MOD; // decrease 1 (the empty grid placement)
}

int Solve(int N, int M) { // full solution in O(N^2)
  vector<vector<int>> dp(N + 1, vector<int>(M + 1, 0)); // dp[current_row][free_column]

  dp[N][M] = 1;
  for (int row = N; row > 0; row--) {
    for (int free_column = 0; free_column <= M; free_column++) {
      // Place 0 tent.
      RADD(dp[row - 1][free_column], dp[row][free_column]);

      // Place 1 tent in the current row, there are 4 * free_column ways to do it.
      if (free_column >= 1) {
        RADD(dp[row - 1][free_column - 1], MUL(free_column, 4, dp[row][free_column]));
      }

      // Place 2 tents with the same row, there are col * (col - 1) / 2 ways to do it. 
      // Afterwards, the number of free columns decreased by 2.
      if (free_column >= 2) {
        RADD(dp[row - 1][free_column - 2], MUL(free_column, free_column - 1, dp[row][free_column], INV2));
      }

      // Place 2 tents with the same column, where one of them is in the current row.
      // Afterwards, there exists a row later on where we cannot place anything, so
      // we can safely assume it is not there. There are free_col ways to choose a column,
      // and N - 1 ways to pick the other pair (the row must be yet to be processed).
      if (row >= 2 && free_column >= 1) {
        RADD(dp[row - 2][free_column - 1], MUL(free_column, row - 1, dp[row][free_column]));
      }
    }
  }

  int res = 0;
  for (int col = 0; col <= M; col++) {
    RADD(res, dp[0][col]);
  }

  return (res - 1 + MOD) % MOD; // decrease 1 for empty grid configuration
}

int main() {
  int N, M;
  cin >> N >> M;
  cout << Solve(N, M) << "\n";
  return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...