Official

D - Dance Editorial by en_translator


It is sufficient to enumerate all the ways to pair \(2N\) participants into \(N\) pairs (hereinafter we simply refer to it as “combination”), and output the maximum total fun among them.
Hereinafter, we take \(N = 8\) as the example, in which there are maximum number of combinations.

Consider the following natural way to choose a combination.

  • Choose one person out of the \(16\) people and assign him/her as the \(1\)-st person of the \(1\)-st pair.
  • Choose one person out of the remaining \(15\) people and assign him/her as the \(2\)-nd person of the \(1\)-st pair.
  • Choose one person out of the remaining \(14\) people and assign him/her as the \(1\)-st person of the \(2\)-nd pair.
  • Choose one person out of the remaining \(13\) people and assign him/her as the \(2\)-nd person of the \(2\)-nd pair.
  • Choose one person out of the remaining \(12\) people and assign him/her as the \(1\)-st person of the \(3\)-rd pair.
  • Choose one person out of the remaining \(11\) people and assign him/her as the \(2\)-nd person of the \(3\)-rd pair.
  • \(\cdots\)
  • Choose one person out of the remaining \(2\) people and assign him/her as the \(1\)-st person of the \(8\)-th pair.
  • Choose one person out of the remaining \(1\) person and assign him/her as the \(2\)-nd person of the \(8\)-th pair.

This brute force search requires \(16 \times 15 \times 14 \times \cdots \times 2 \times 1 > 2 \times 10^{13}\) iterations of combinations, which does not fit in the time limit.

The iteration above is redundant in that the same combination is inspected multiple times.

For example, let us denote by \(x_{i, 1}\) the \(1\)-st person of the \(i\)-th pair and by \(x_{i, 2}\) the \(2\)-nd. Then the following three combinations are inspected as different choices, but they are essentially the same.

  • \(\big((x_{1, 1}, x_{1, 2}), (x_{2, 1}, x_{2, 2}), \ldots, (x_{8, 1}, x_{8, 2})\big) = \big((1, 2), (3, 4), \ldots, (15, 16)\big)\)

  • \(\big((x_{1, 1}, x_{1, 2}), (x_{2, 1}, x_{2, 2}), \ldots, (x_{8, 1}, x_{8, 2})\big) = \big((2, 1), (4, 3), \ldots, (16, 15)\big)\)

  • \(\big((x_{1, 1}, x_{1, 2}), (x_{2, 1}, x_{2, 2}), \ldots, (x_{8, 1}, x_{8, 2})\big) = \big((15, 16), (13, 14), \ldots, (1, 2)\big)\)

In order to handle this issue, revise the searching algorithm above so that “the person with the minimum index is always assigned as the \(1\)-st person of each pair.” In other words, we adopt the following algorithm:

  • Let the \(1\)-st person of the \(1\)-st pair be the person with the minimum index among the \(16\) people (i.e., choose Person \(1\)).
  • Choose one person out of the remaining \(16\) people and assign him/her as the \(2\)-nd person of the \(1\)-st pair.
  • Let the \(1\)-st person of the \(2\)-nd pair be the person with the minimum index among the remaining \(14\) people.
  • Choose one person out of the remaining \(13\) people and assign him/her as the \(2\)-nd person of the \(2\)-nd pair.
  • Let the \(1\)-st person of the \(3\)-rd pair be the person with the minimum index among the remaining \(12\) people.
  • Choose one person out of the remaining \(11\) people and assign him/her as the \(2\)-nd person of the \(3\)-rd pair.
  • \(\cdots\)
  • Let the \(1\)-st person of the \(8\)-th pair be the person with the minimum index among the remaining \(2\) people.
  • Choose one person out of the remaining \(1\) person and assign him/her as the \(2\)-nd person of the \(8\)-th pair.

While exhaustively enumerating all the combinations, the \(1\)-st person of each pair is always uniquely determined, so it requires \(15 \times 13 \times 11 \times 9 \times 7 \times 5 \times 3 \times 1 =2027025\) iterations, which fits in the time limit.

A sample code in C++ language is shown below.

#include <iostream>
#include <vector>
#include <utility>
using namespace std;

int n;
int a[20][20];

vector<pair<int, int>> vec;
bool used[20];

int calc()
{
  if(vec.size() == n){
    int ret = 0;
    for(auto p : vec) ret ^= (a[p.first][p.second]);
    return ret;
  }
  
  int l;
  for(int i = 1; i <= 2*n; i++){
    if(!used[i]){
      l = i;
      break;
    }
  }
  used[l] = true;

  int ret = 0;
  for(int i = 1; i <= 2*n; i++){
    if(!used[i]){
      vec.push_back({l, i}), used[i] = true;
      ret = max(ret, calc());
      vec.pop_back(), used[i] = false;
    }
  }
    
  used[l] = false;
  return ret;
}

int main(void)
{
  cin >> n;
  for(int i = 1; i <= 2*n-1; i++){
    for(int j = i+1; j <= 2*n; j++){
      cin >> a[i][j];
    }
  }
  cout << calc() << endl;

  return 0;
}

posted:
last update: