This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
int ADD() { return 0; }
int MUL() { return 1; }
template<typename... Tail> int ADD(int H, Tail... T) {
  return ((H += ADD(T...)) >= MOD) ? H - MOD : H;
}
template<typename...Tail> int MUL(int H, Tail...T) {
  return 1ll * H * MUL(T...) % MOD;
}
const int MAXN = 1205;
int N;
int A[MAXN];
bool is_special[MAXN];
int C[MAXN][MAXN]; // binomial coefficent
int ways[MAXN][MAXN];
int total_ways[MAXN];
int dp[MAXN][MAXN];
void Read() {
  cin >> N;
  for (int i = 1; i <= N; i++) {
    cin >> A[i];
    is_special[A[i]] = true;
  }
}
void InitBinomial() {
  C[0][0] = 1;
  for (int i = 1; i <= 2 * N; i++) {
    for (int j = 0; j <= i; j++) {
      C[i][j] = ADD(C[i - 1][j], (j > 0 ? C[i - 1][j - 1] : 0));
    }
  }
}
void CountWays() {
  for (int l = 1; l <= N; l++) {
    // ways[i][j] = number of ways of choosing and permuting j integers from the set {1, 1, 2, 2, ..., i, i} 
    // (each element appears twice), such that the first element is l, and the following holds: p[i] >= i if 
    // we sort p, where p is the permutation chosen.
    
    ways[0][1] = 2; // the element l is already in the front of the set, of which there are two kinds
    for (int i = 1; i <= N; i++) { // we consider placing element i into the set
      for (int j = 0; j <= i; j++) { // the number of elements that we have picked. 
        // Note that i >= j always holds, and since j is the current position index and i is the element, 
        // p[i] >= i holds when sorted.
        ways[i][j] = 0; // reset
        if (i == l) {
          ways[i][j] = ADD(ways[i][j], ways[i - 1][j]); // we place element l into the front, of which there remains only one kind
          if (j >= 1) {
            ways[i][j] = ADD(ways[i][j], MUL(ways[i - 1][j - 1], j - 1)); // we place one of element l in one of the gaps
          }
        } else {
          ways[i][j] = ADD(ways[i][j], ways[i - 1][j]); // we do not place element i into the set
          if (j >= 1) {
            // We place a single element i into the set. Since we consider two pillars with height i different, 
            // we multiply it by 2. We can place the new element to j positions relative to the elements currently 
            // inside (ways[i - 1] have j - 1 elements, and there are j gaps between these elements that we can 
            // place the new element into). However, because we have already placed element l in the front, we cannot
            // place i in the front, so the possible gaps decrease by 1.
            ways[i][j] = ADD(ways[i][j], MUL(2, ways[i - 1][j - 1], j - 1));
          }
          if (j >= 2)  {
            ways[i][j] = ADD(ways[i][j], MUL(ways[i - 1][j - 2], j - 2, 2)); // we place both elements in the same gap. We can permute the new elements by 2!, so we multiply it by 2.
            ways[i][j] = ADD(ways[i][j], MUL(ways[i - 1][j - 2], j - 2, j - 3)); // we place both elements in different gaps
          }
        }
      }
    }
    for (int i = l; i <= N; i++) {
      total_ways[i] = ADD(total_ways[i], ways[i][i]); // ways[l][k][k] contributes to total_ways[k], since total_ways[k] = sum of ways[l][k][k] for l = 1, 2, ..., k.
    }
  }
}
void CalculateDP() {
  dp[2 * N][0] = 1; // dp[pos][height] = we have placed special pillars of height 1, 2, 3, ..., height and all pillars pos + 1, pos + 2, ..., 2N
  int special = 0, non_special = 0; // count special and non-special positions that we have encountered
  for (int pos = 2 * N; pos >= 1; pos--) {
    if (is_special[pos]) { // now current pillar is special
      for (int new_height = 0; new_height <= N; new_height++) { // new bound
        dp[pos - 1][new_height] = ADD(dp[pos - 1][new_height], dp[pos][new_height]); // we leave the current special pillar slot unfilled
        for (int cur_height = 0; cur_height < min(new_height, special + 1); cur_height++) { 
          // we fill the special pillar slot, and since we have filled exactly cur_height special positions, there are 
          // special - cur_height positions left. Since we add (add) new special pillars, and one of them must be at 
          // current position, we multiply it by C[special - cur_height][add - 1].
          int add = new_height - cur_height;
          dp[pos - 1][new_height] = ADD(dp[pos - 1][new_height], MUL(dp[pos][cur_height], C[special - cur_height][add - 1], total_ways[add])); 
          // we place a special pillar of height cur_height + 1 at the current position, to avoid double counting. 
          // The number of ways to achieve this is total_ways[add] = for all l = 1...add, if we place l at the front, 
          // how many ways are there to get a valid sequence that after earthqueakes, elements 1, 2, ..., add are left, 
          // such that the first element is 1? Since the final height of the first element is 1, it corresponds to
          // the final height of the pillar at the current position as cur_hegiht + 1 (since we are adding pillars with
          // height cur_height + 1, cur_height + 2, ..., final_height).
        }
      }
      special++;
    } else { // current pillar is not special
      for (int j = non_special; j <= special; j++) {
        // we have (j - non_special) pillars we can add without breaking rules (since adding a pillar of new height means 
        // that pillar must be special (and this location is not), we cannot place a new height).
        dp[pos - 1][j] = MUL(dp[pos][j], j - non_special); 
      }
      non_special++;
    }
  }
}
int Answer() {
  int res = dp[0][N];
  for (int i = 0; i < N; i++) {
    if (res & 1) res += MOD;
    res /= 2; // we previoiusly considered 2 pillars with the same height different, but in actuality they are the same. Thus we divide everything by 2^N
  }
  return res;
}
int main() {
  Read();
  
  InitBinomial();
  CountWays();
  CalculateDP();
  
  cout << Answer() << "\n";
  return 0;
}
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict  | Execution time | Memory | Grader output | 
|---|
| Fetching results... |