// competitive-verifier: PROBLEM https://yukicoder.me/problems/no/2883 #include #include #include #include #include #include using uint = unsigned; using ull = unsigned long long; constexpr uint MOD = 1000000007; constexpr uint PowMod(uint a, ull e) { for (uint res = 1;; a = (ull)a * a % MOD) { if (e & 1) res = (ull)res * a % MOD; if ((e /= 2) == 0) return res; } } constexpr uint InvMod(uint a) { return PowMod(a, MOD - 2); } // returns */Q in F((x^-1)) such that */Q = A[0]*x^-1 + A[1]*x^-2 + ... // with deg(Q) minimized. std::vector BerlekampMassey(std::vector A) { reverse(begin(A), end(A)); int k = size(A), degA = k - 1, degB = k; std::vector B(k + 1), Q0, Q1 = {1U}; for (B[k] = 1;; swap(Q0, Q1), swap(A, B), std::swap(degA, degB)) { while (degA >= 0 && A[degA] == 0) --degA; if (degA < 0 || degA - degB < -k) return Q1; Q0.resize(size(Q1) + (degB - degA)); k -= (degB - degA) * 2; const uint a = InvMod(A[degA]); for (int i = degB - degA; i >= std::max(-k, 0); --i) { const uint d = (ull)B[degB--] * a % MOD; for (int j = 0; j <= degA; ++j) B[i + j] = (B[i + j] + (ull)A[j] * (MOD - d)) % MOD; for (int j = 0; j < (int)size(Q1); ++j) Q0[i + j] = (Q0[i + j] + (ull)Q1[j] * d) % MOD; } } } // returns [x^[-deg(Q), 0)] x^k/Q, x^k/Q in F((x^-1)) std::vector BostanMoriT(const std::vector &Q, long long k) { assert(k >= 0); const int degQ = size(Q) - 1; std::vector U(degQ); if (k == 0) return U[0] = InvMod(Q.back()), U; std::vector V(size(Q)); for (int i = 0; i < (int)size(Q); ++i) for (int j = i % 2; j < (int)size(Q); j += 2) V[(i + j) / 2] = (V[(i + j) / 2] + (ull)Q[i] * (i % 2 == 0 ? Q[j] : MOD - Q[j])) % MOD; const auto T = BostanMoriT(V, k / 2); for (int i = 0; i < (int)size(T); ++i) for (int j = 0; j < (int)size(Q); ++j) { const int l = i * 2 + (int)(k % 2) + j; if (l >= degQ && l < degQ * 2) U[l - degQ] = (U[l - degQ] + (ull)T[i] * (j % 2 == 0 ? Q[j] : MOD - Q[j])) % MOD; } return U; } // returns x^k mod Q std::vector MonomialModPoly(long long k, const std::vector &Q) { const auto invQ = BostanMoriT(Q, k); std::vector R(size(Q) - 1); for (int i = 0; i < (int)size(invQ); ++i) for (int j = 0; j < (int)size(Q); ++j) if (i + j >= (int)size(invQ)) R[i + j - (int)size(invQ)] = (R[i + j - (int)size(invQ)] + (ull)invQ[i] * Q[j]) % MOD; return R; } uint BMBM(const std::vector &A, long long k) { const auto c = MonomialModPoly(k, BerlekampMassey(A)); uint res = 0; for (int i = 0; i < (int)size(c); ++i) res = (res + (ull)c[i] * A[i]) % MOD; return res; } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); long long N; std::cin >> N; uint dp[50][0b1000] = {}; dp[1][0b1] = 1; dp[1][0b10] = 1; dp[1][0b100] = 1; dp[1][0b11] = 1; dp[1][0b110] = 1; dp[1][0b111] = 1; for (int i = 2; i < 50; ++i) { for (int j = 0b1; j <= 0b111; ++j) { if (j == 0b101) { dp[i][j] = ((ull)dp[i][j] + dp[i - 1][0b111] + dp[i - 1][0b101]) % MOD; continue; } for (int k = 0b1; k <= 0b111; ++k) { if (k == 0b101) { if (j == 0b11 || j == 0b110) continue; if (j == 0b111) { dp[i][j] = (dp[i][j] + 1) % MOD; if (i > 2) { for (int k = 1; k <= i - 2; ++k) { dp[i][j] = ((ull)dp[i][j] + dp[k][0b1] + dp[k][0b100]) % MOD; } } continue; } } if ((j & k) > 0) dp[i][j] = (dp[i][j] + dp[i - 1][k]) % MOD; } } } auto sum = [&](int r) { uint res = 0; for (int i = 0b1; i <= 0b111; ++i) res = (res + dp[r][i]) % MOD; return res; }; std::vector A(49); for (int i = 1; i < 50; ++i) { for (int j = 1; j <= i; ++j) { A[i - 1] = (A[i - 1] + (ull)sum(j) * (i - j + 1)) % MOD; } // std::cout << A[i - 1] << '\n'; } std::cout << BMBM(A, N - 1) << '\n'; return 0; }