AOJ 2025 - Eight Princes

現実逃避

問題

n個の椅子がある円卓がある。
ここに8人の王子が座る。
ただし、王子が隣り合ったり、ちょうど向かい合ったりしてはいけない。
このとき、何通りの座り方があるか。
回転したり反転したりして同じになるものも区別して数える。

制約

答えは10^14以下

解法

奇数のときは向かい合うことは無いので、ありきたりのDPで出来る。
偶数のときは、向かい合う椅子をセットで考えることがポイント。
各セットに対し、座らない、前半分のほうに座る、後半分の方に座る、という3パターンに分けることが出来る。
こう考えると、各セットに対して順番に座らせていくDPが可能になる。
状態の持ち方や更新の仕方は色々やり方があると思う。

ソース

// dp[何人座ったか][何番目の椅子まで見たか][最初の椅子に座ってない/座ってた][直前の椅子に座ってない/座った]
ll dp[10][101][2][2];

void odd_init() {
  dp[0][1][0][0] = dp[1][1][1][1] = 1;
  REP(i,9) {
    for (int j=1; j<100; ++j) {
      REP(k,2) {
        dp[i][j+1][k][0] += dp[i][j][k][0] + dp[i][j][k][1];
        dp[i+1][j+1][k][1] += dp[i][j][k][0];
      }
    }
  }
}

// dp2[何人座ったか][何番目の椅子まで見たか][最初の椅子に座ってない/前半に座った/後半に座った][直前の椅子に座ってない/前半に座った/後半に座った]
ll dp2[10][101][3][3];

void even_init() {
  dp2[0][1][0][0] = dp2[1][1][1][1] = dp2[1][1][2][2] = 1;
  REP(i,9) {
    for (int j=1; j<100; ++j) {
      REP(k,3) {  
        dp2[i][j+1][k][0] += dp2[i][j][k][0] + dp2[i][j][k][1] + dp2[i][j][k][2];
        dp2[i+1][j+1][k][1] += dp2[i][j][k][0] + dp2[i][j][k][2];
        dp2[i+1][j+1][k][2] += dp2[i][j][k][0] + dp2[i][j][k][1];
      }
    }
  }
}

// 最初の椅子と最後の椅子に同時に座ることが内容に足し合わせる。
// 40320は8!
ll solve_odd(int n) {
  return (dp[8][n][0][0] + dp[8][n][0][1] + dp[8][n][1][0]) * 40320;
}

// 最初のセットと最後のセットの座り方に注意して足し合わせる。
ll solve_even(int n) {
  ll ans = 0;
  REP(i,3) REP(j,3) {
    if (i==1&&j==2 || i==2&&j==1) continue;
    ans += dp2[8][n/2][i][j];
  }
  return ans * 40320;
}

int main() {
  odd_init();
  even_init();
  int n;
  while(cin>>n,n) {
    if (n&1) {
      cout << solve_odd(n) << endl;
    } else {
      cout << solve_even(n) << endl;
    }
  }
}