結果
問題 | No.93 ペガサス |
ユーザー | codershifth |
提出日時 | 2015-08-30 14:54:43 |
言語 | C++11 (gcc 11.4.0) |
結果 |
AC
|
実行時間 | 424 ms / 5,000 ms |
コード長 | 8,761 bytes |
コンパイル時間 | 1,704 ms |
コンパイル使用メモリ | 177,636 KB |
実行使用メモリ | 152,192 KB |
最終ジャッジ日時 | 2024-07-18 15:38:36 |
合計ジャッジ時間 | 4,289 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
6,812 KB |
testcase_01 | AC | 2 ms
6,940 KB |
testcase_02 | AC | 1 ms
6,944 KB |
testcase_03 | AC | 1 ms
6,940 KB |
testcase_04 | AC | 64 ms
26,240 KB |
testcase_05 | AC | 22 ms
11,264 KB |
testcase_06 | AC | 14 ms
8,448 KB |
testcase_07 | AC | 227 ms
84,608 KB |
testcase_08 | AC | 107 ms
41,216 KB |
testcase_09 | AC | 407 ms
148,480 KB |
testcase_10 | AC | 3 ms
6,940 KB |
testcase_11 | AC | 9 ms
6,940 KB |
testcase_12 | AC | 338 ms
123,776 KB |
testcase_13 | AC | 94 ms
36,608 KB |
testcase_14 | AC | 33 ms
15,232 KB |
testcase_15 | AC | 315 ms
109,696 KB |
testcase_16 | AC | 46 ms
19,072 KB |
testcase_17 | AC | 1 ms
6,940 KB |
testcase_18 | AC | 1 ms
6,944 KB |
testcase_19 | AC | 424 ms
152,192 KB |
ソースコード
#include <bits/stdc++.h> typedef long long ll; typedef unsigned long long ull; #define FOR(i,a,b) for(int (i)=(a);i<(b);i++) #define REP(i,n) FOR(i,0,n) #define RANGE(vec) (vec).begin(),(vec).end() class ModInt { long long value_; public: static long long Mod; static void set_mod(long long mod) { Mod= mod; } static long long get_mod(void) { return Mod; } ModInt() : value_(0) {} ModInt(long long val) { if (val >= Mod) value_ = val % Mod; else if (val >= 0) value_ = val; else // val < 0 value_ = (((-val)/Mod+1)*Mod+val) % Mod; assert(value_ < Mod); } ModInt(const ModInt &other) { value_ = other.value_; } ~ModInt() {} #define OPT(OP) \ ModInt operator OP (const ModInt &other) const { \ return ModInt(value_ OP other.value_); \ } \ template<class T> \ ModInt &operator OP##=(const T &other) { \ return (*this = (*this OP ModInt(other))); \ } OPT(+) OPT(-) OPT(*) #undef OPT bool operator==(const ModInt &other) const { return (value_ == other.value_); } bool operator!=(const ModInt &other) const { return !(*this == other); } ModInt &operator=(const ModInt &other) { value_ = other.value_; return *this; } // cast overload operator int() const { return value_; } operator long long() const { return value_; } static long long pow(ModInt a, int k) { ModInt b = 1; while (k > 0) { if (k & 1) b = (b*a); a = (a*a); k >>= 1; } return b; } // call when Mod is prime ModInt inv() { return ModInt::pow(*this, Mod-2); } long long value() const { return value_; } friend std::ostream& operator<<(std::ostream& os, const ModInt& m) { os<<m.value_; return os; } }; // 互換性サポートは int, long long のみ #define OPT(OP,T) \ ModInt operator OP (const ModInt &a, T b) { return a OP ModInt(b); } \ ModInt operator OP (T a, const ModInt &b) { return ModInt(a) OP b; } OPT(*,int) OPT(+,int) OPT(-,int) OPT(*,long long) OPT(+,long long) OPT(-,long long) #undef OPT long long ModInt::Mod = (long long)(1E+9)+7; namespace multi_dimentional_vector { template<typename T> void resize(std::vector<T> &vec, size_t sz) { vec.resize(sz); } template<typename T, typename S> void resize(std::vector<T> &vec, size_t sz, const S &init) { vec.resize(sz, static_cast<T>(init)); } template<typename T, typename... S> void resize(std::vector<T> &vec, size_t sz, const S&... follows) { vec.resize(sz); for (auto &v : vec) resize(v, follows...); } template <typename T> struct has_iterator { template <typename U> static char test(typename U::iterator* x); template <typename U> static long test(U* x); static const bool value = sizeof(test<T>(0)) == 1; }; template <typename T, typename S> typename std::enable_if<!has_iterator<T>::value, void>::type fill(std::vector<T>& vec, const S &value) { std::fill(vec.begin(), vec.end(), static_cast<T>(value)); } template <typename T, typename S> typename std::enable_if<has_iterator<T>::value, void>::type fill(std::vector<T>& vec, const S &value) { for (auto &v : vec) fill(v, value); } template<typename T, typename... S> std::vector<T> define(size_t sz, const S&... follows) { std::vector<T> vec; return std::move(vec); } }; namespace mdv = multi_dimentional_vector; using namespace std; class Pegasus { public: void solve(void) { // // 縦横にはおけないのと N*N 盤面であることから // // +-+-+-+-+ // | |o| | | // +-+-+-+-+ // |o| | | | // +-+-+-+-+ // | | | |o| // +-+-+-+-+ // | | |o| | // +-------+ // [2,1,4,3] // // のように 1...n の順列のうち隣り合う数字との差の絶対値が // 2 にならないようなものの総数を求めれば良い。 // 以下隣接する数字の差の絶対値が 2 になる条件を cond と表す。 // // 挿入 DP でやる。 // 1,2,3,..,N の順に挿入して順列をつくると考える。 // // 1,2,..,n の順列にたいして n+1 を挿入する時 // * n-1 の隣に挿入してしまうと cond をみたすものが 1 つできる。 // (1,2,... の順で挿入するので片側だけ考えれば良い。) // * ただし n-3,n-1 が隣接するとき間に cond を満たすものの総数は変わらない ((-1) + (+1) = 0) // * それ以外の cond をみたす隣接2数の間に挿入すれば cond を満たすものの総数を減らせる。 // // n+1 の挿入時に n-3,n-1 が隣接しているかの情報が必要になる。 // つまり次の更新時のために n,n-2 が隣り合うかの情報更新が必要。 // // 以上を踏まえると dp は // dp[n][k][a][b] := n 番目まで挿入したときに、 cond をみたす場所が k 個あるときの挿入結果の総数 // ただし a==1 のとき (n-3,n-1) が隣接 // ただし b==1 のとき (n-2,n) が隣接 // // となる。 int N; cin>>N; vector<vector<vector<vector<ModInt>>>> dp; mdv::resize(dp, N+1, N+1, 2, 2, 0); dp[1][0][0][0] = 1; // O(N^2) FOR(n,1,N) REP(k,N) REP(a,2) REP(b,2) { if (n == 1) { // 1 枚しかないときはどこに挿入しても cond を満たさない dp[n+1][k][0][0] += (n+1)*dp[n][k][a][b]; continue; } // (n-2,n) -> (n-3,n-1) // (n-1,n+1) -> (n-2,n) if (a==1) // (n-3,n-1) が隣接 { // n-1 のとなりに挿入するケース // (n-3,n-1) の間に挿入 dp[n+1][k][b][1] += dp[n][k][a][b]; // (n-3,n-1)じゃないほうの n-1 のとなり dp[n+1][k+1][b][1] += dp[n][k][a][b]; // cond 総数を減らすような挿入。 k-1 なのは上の (n-3,n-1) のケースを省くから if (k >= 1) { if (b==1) // (n-2,n) が隣接するケース { // (n-2,n) の間に挿入 dp[n+1][k-1][0][0] += dp[n][k][a][b]; // それ以外 dp[n+1][k-1][1][0] += ((k-1)-1)*dp[n][k][a][b]; } else dp[n+1][k-1][b][0] += (k-1)*dp[n][k][a][b]; } // のこり (n+1) なのは 1,...,n の両側を含めるから dp[n+1][k][b][0] += ((n+1)-k-1)*dp[n][k][a][b]; } else { // n-1 のとなりに挿入(左右二通り) dp[n+1][k+1][b][1] += 2*dp[n][k][a][b]; // k を減らすような挿入 if (k >= 1) { if (b==1) { // (n-2,n) の間に挿入 dp[n+1][k-1][0][0] += dp[n][k][a][b]; // それ以外 dp[n+1][k-1][1][0] += (k-1)*dp[n][k][a][b]; } else dp[n+1][k-1][b][0] += k*dp[n][k][a][b]; } // のこり dp[n+1][k][b][0] += ((n+1)-k-2)*dp[n][k][a][b]; } } cout<<dp[N][0][0][0]<<endl; } }; #if 1 int main(int argc, char *argv[]) { ios::sync_with_stdio(false); auto obj = new Pegasus(); obj->solve(); delete obj; return 0; } #endif