Submission #17173142
Source Code Expand
#include <algorithm>
#include <array>
#include <cassert>
#include <iostream>
#include <vector>
using namespace std;
template<typename T> ostream& operator<<(ostream &os, const vector<T> &v) { os << '{'; string sep; for (const auto &x : v) os << sep << x, sep = ", "; return os << '}'; }
template<typename T, size_t size> ostream& operator<<(ostream &os, const array<T, size> &arr) { os << '{'; string sep; for (const auto &x : arr) os << sep << x, sep = ", "; return os << '}'; }
template<typename A, typename B> ostream& operator<<(ostream &os, const pair<A, B> &p) { return os << '(' << p.first << ", " << p.second << ')'; }
void dbg_out() { cerr << endl; }
template<typename Head, typename... Tail> void dbg_out(Head H, Tail... T) { cerr << ' ' << H; dbg_out(T...); }
#ifdef NEAL_DEBUG
#define dbg(...) cerr << "(" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__)
#else
#define dbg(...)
#endif
template<const int &MOD>
struct _m_int {
int val;
_m_int(int64_t v = 0) {
if (v < 0) v = v % MOD + MOD;
if (v >= MOD) v %= MOD;
val = int(v);
}
_m_int(uint64_t v) {
if (v >= MOD) v %= MOD;
val = int(v);
}
_m_int(int v) : _m_int(int64_t(v)) {}
_m_int(unsigned v) : _m_int(uint64_t(v)) {}
static int inv_mod(int a, int m = MOD) {
// https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Example
int g = m, r = a, x = 0, y = 1;
while (r != 0) {
int q = g / r;
g %= r; swap(g, r);
x -= q * y; swap(x, y);
}
return x < 0 ? x + m : x;
}
explicit operator int() const { return val; }
explicit operator unsigned() const { return val; }
explicit operator int64_t() const { return val; }
explicit operator uint64_t() const { return val; }
explicit operator double() const { return val; }
explicit operator long double() const { return val; }
_m_int& operator+=(const _m_int &other) {
val -= MOD - other.val;
if (val < 0) val += MOD;
return *this;
}
_m_int& operator-=(const _m_int &other) {
val -= other.val;
if (val < 0) val += MOD;
return *this;
}
static unsigned fast_mod(uint64_t x, unsigned m = MOD) {
#if !defined(_WIN32) || defined(_WIN64)
return unsigned(x % m);
#endif
// Optimized mod for Codeforces 32-bit machines.
// x must be less than 2^32 * m for this to work, so that x / m fits in an unsigned 32-bit int.
unsigned x_high = unsigned(x >> 32), x_low = unsigned(x);
unsigned quot, rem;
asm("divl %4\n"
: "=a" (quot), "=d" (rem)
: "d" (x_high), "a" (x_low), "r" (m));
return rem;
}
_m_int& operator*=(const _m_int &other) {
val = fast_mod(uint64_t(val) * other.val);
return *this;
}
_m_int& operator/=(const _m_int &other) {
return *this *= other.inv();
}
friend _m_int operator+(const _m_int &a, const _m_int &b) { return _m_int(a) += b; }
friend _m_int operator-(const _m_int &a, const _m_int &b) { return _m_int(a) -= b; }
friend _m_int operator*(const _m_int &a, const _m_int &b) { return _m_int(a) *= b; }
friend _m_int operator/(const _m_int &a, const _m_int &b) { return _m_int(a) /= b; }
_m_int& operator++() {
val = val == MOD - 1 ? 0 : val + 1;
return *this;
}
_m_int& operator--() {
val = val == 0 ? MOD - 1 : val - 1;
return *this;
}
_m_int operator++(int) { _m_int before = *this; ++*this; return before; }
_m_int operator--(int) { _m_int before = *this; --*this; return before; }
_m_int operator-() const {
return val == 0 ? 0 : MOD - val;
}
friend bool operator==(const _m_int &a, const _m_int &b) { return a.val == b.val; }
friend bool operator!=(const _m_int &a, const _m_int &b) { return a.val != b.val; }
friend bool operator<(const _m_int &a, const _m_int &b) { return a.val < b.val; }
friend bool operator>(const _m_int &a, const _m_int &b) { return a.val > b.val; }
friend bool operator<=(const _m_int &a, const _m_int &b) { return a.val <= b.val; }
friend bool operator>=(const _m_int &a, const _m_int &b) { return a.val >= b.val; }
_m_int inv() const {
return inv_mod(val);
}
_m_int pow(int64_t p) const {
if (p < 0)
return inv().pow(-p);
_m_int a = *this, result = 1;
while (p > 0) {
if (p & 1)
result *= a;
p >>= 1;
if (p > 0)
a *= a;
}
return result;
}
friend ostream& operator<<(ostream &os, const _m_int &m) {
return os << m.val;
}
};
extern const int MOD = 1e9 + 7;
using mod_int = _m_int<MOD>;
vector<mod_int> inv, factorial, inv_factorial;
int prepared_maximum = -1;
void prepare_factorials(int64_t maximum) {
static int prepare_calls = 0;
if (prepare_calls++ == 0) {
// Make sure MOD is prime, which is necessary for the inverse algorithm below.
for (int p = 2; p * p <= MOD; p += p % 2 + 1)
assert(MOD % p != 0);
inv = {0, 1};
factorial = inv_factorial = {1, 1};
prepared_maximum = 1;
}
if (maximum > prepared_maximum) {
inv.resize(maximum + 1);
factorial.resize(maximum + 1);
inv_factorial.resize(maximum + 1);
for (int i = prepared_maximum + 1; i <= maximum; i++) {
inv[i] = inv[MOD % i] * (MOD - MOD / i);
factorial[i] = i * factorial[i - 1];
inv_factorial[i] = inv[i] * inv_factorial[i - 1];
}
prepared_maximum = int(maximum);
}
}
mod_int choose(int64_t n, int64_t r) {
if (r < 0 || r > n) return 0;
return factorial[n] * inv_factorial[r] * inv_factorial[n - r];
}
mod_int inv_choose(int64_t n, int64_t r) {
assert(0 <= r && r <= n);
return inv_factorial[n] * factorial[r] * factorial[n - r];
}
mod_int permute(int64_t n, int64_t r) {
if (r < 0 || r > n) return 0;
return factorial[n] * inv_factorial[n - r];
}
mod_int inv_permute(int64_t n, int64_t r) {
assert(0 <= r && r <= n);
return inv_factorial[n] * factorial[n - r];
}
// https://en.wikipedia.org/wiki/Bernoulli_number
vector<mod_int> bernoulli;
void prepare_bernoulli(int maximum) {
bernoulli.resize(maximum + 1);
for (int m = 0; m <= maximum; m++) {
bernoulli[m] = 1;
for (int k = 0; k < m; k++)
bernoulli[m] -= choose(m, k) * bernoulli[k] * inv[m - k + 1];
}
}
using polynomial = vector<mod_int>;
mod_int evaluate(const polynomial &poly, mod_int x) {
mod_int result = 0, power = 1;
for (int i = 0; i < int(poly.size()); i++) {
result += poly[i] * power;
power *= x;
}
return result;
}
polynomial& operator+=(polynomial &a, const polynomial &b) {
a.resize(max(a.size(), b.size()), 0);
for (int i = 0; i < int(b.size()); i++)
a[i] += b[i];
return a;
}
polynomial operator+(polynomial a, const polynomial &b) {
return a += b;
}
polynomial& operator-=(polynomial &a, const polynomial &b) {
a.resize(max(a.size(), b.size()), 0);
for (int i = 0; i < int(b.size()); i++)
a[i] -= b[i];
return a;
}
polynomial operator-(polynomial a, const polynomial &b) {
return a -= b;
}
polynomial& operator*=(polynomial &poly, mod_int mult) {
for (int i = 0; i < int(poly.size()); i++)
poly[i] *= mult;
return poly;
}
polynomial operator*(polynomial poly, mod_int mult) {
return poly *= mult;
}
polynomial operator*(mod_int mult, const polynomial &poly) {
return poly * mult;
}
polynomial operator*(const polynomial &a, const polynomial &b) {
if (a.empty() || b.empty())
return {};
// return NTT::mod_multiply(a, b);
static const uint64_t U64_BOUND = numeric_limits<uint64_t>::max() - uint64_t(MOD) * MOD;
vector<uint64_t> result(a.size() + b.size() - 1, 0);
for (int i = 0; i < int(a.size()); i++)
for (int j = 0; j < int(b.size()); j++) {
result[i + j] += uint64_t(a[i]) * uint64_t(b[j]);
if (result[i + j] > U64_BOUND)
result[i + j] %= MOD;
}
for (uint64_t &x : result)
if (x >= MOD)
x %= MOD;
return vector<mod_int>(result.begin(), result.end());
}
polynomial& operator*=(polynomial &a, const polynomial &b) {
return a = a * b;
}
// Returns 1^k + 2^k + ... + x^k as a polynomial in x.
polynomial sum_of_powers(int k) {
polynomial result(k + 2, 0);
// https://en.wikipedia.org/wiki/Faulhaber%27s_formula
for (int a = 0; a <= k; a++)
result[k - a + 1] = bernoulli[a] * inv_factorial[a] * factorial[k] * inv_factorial[k - a + 1];
return result;
}
// Returns the sum P(0) + P(1) + ... + P(x) as a polynomial in x.
polynomial partial_sum(const polynomial &poly) {
if (poly.empty())
return {};
polynomial result(poly.size() + 1, 0);
result[1] = poly[0];
// To exclude P(0) from the sum, remove the following line.
result[0] = poly[0];
// for (int k = 1; k < int(poly.size()); k++) {
// // result += sum_of_powers(k) * poly[k];
// for (int a = 0; a <= k; a++)
// result[k - a + 1] += bernoulli[a] * inv_factorial[a] * factorial[k] * inv_factorial[k - a + 1] * poly[k];
// }
vector<mod_int> a_half(poly.size(), 0);
vector<mod_int> k_half(poly.size(), 0);
for (int a = 0; a < int(poly.size()); a++)
a_half[a] = bernoulli[a] * inv_factorial[a];
reverse(a_half.begin(), a_half.end());
for (int k = 1; k < int(poly.size()); k++)
k_half[k] = factorial[k] * poly[k];
vector<mod_int> product = a_half * k_half;
for (int i = 1; i <= int(poly.size()); i++)
result[i] += product[i + poly.size() - 2] * inv_factorial[i];
return result;
}
// Finds the length of the longest subsequence of values such that compare is true for all consecutive pairs.
template<typename T, typename T_compare>
int longest_increasing_subsequence(vector<T> values, T_compare &&compare) {
vector<T> best_ending;
for (T value : values) {
auto it = lower_bound(best_ending.begin(), best_ending.end(), value, compare);
if (it == best_ending.end())
best_ending.push_back(value);
else
*it = value;
}
return int(best_ending.size());
}
const int POLY = 100;
const int INF = 1e9 + 10;
int main() {
prepare_factorials(POLY + 5);
prepare_bernoulli(POLY);
auto piecewise_partial_sum = [](vector<pair<array<int, 2>, polynomial>> piecewise, int start, int end) -> vector<pair<array<int, 2>, polynomial>> {
auto get_sum = [&](int x) {
polynomial p;
for (auto &pr : piecewise)
if (pr.first[0] <= x) {
polynomial sum_poly = partial_sum(pr.second);
if (x >= pr.first[1])
p += polynomial{evaluate(sum_poly, pr.first[1]) - evaluate(sum_poly, pr.first[0] - 1)};
else
p += sum_poly - polynomial{evaluate(sum_poly, pr.first[0] - 1)};
}
return p;
};
vector<array<int, 2>> ranges;
for (auto &pr : piecewise)
ranges.push_back(pr.first);
while (!ranges.empty() && start > ranges.front()[1])
ranges.erase(ranges.begin());
while (!ranges.empty() && end < ranges.back()[0])
ranges.pop_back();
if (ranges.empty()) {
ranges = {{start, end}};
} else {
if (start < ranges.front()[0])
ranges.insert(ranges.begin(), array<int, 2>{start, ranges.front()[0] - 1});
else
ranges.front()[0] = start;
if (end > ranges.back()[1])
ranges.push_back({ranges.back()[1] + 1, end});
else
ranges.back()[1] = end;
}
vector<pair<array<int, 2>, polynomial>> next_piecewise;
for (auto &range : ranges)
next_piecewise.emplace_back(range, get_sum(range[0]));
return next_piecewise;
};
auto solve_ranges = [&](vector<array<int, 2>> ranges) {
ranges.push_back({INF, INF});
vector<pair<array<int, 2>, polynomial>> piecewise = {{{0, 0}, {1}}};
for (auto &range : ranges) {
piecewise = piecewise_partial_sum(piecewise, range[0], range[1]);
// dbg(range, piecewise);
}
assert(piecewise.size() == 1);
return evaluate(piecewise[0].second, INF);
};
auto solve_ranges_slow = [](vector<array<int, 2>> ranges) {
int big = 0;
for (auto &range : ranges)
big = max(big, range[1]);
vector<mod_int> dp(big + 1, 0);
dp[0] = 1;
for (auto &range : ranges) {
vector<mod_int> next_dp(big + 1, 0);
mod_int sum = 0;
for (int i = 0; i < range[0]; i++)
sum += dp[i];
for (int i = range[0]; i <= range[1]; i++) {
sum += dp[i];
next_dp[i] = sum;
}
swap(dp, next_dp);
}
mod_int ways = 0;
for (int i = 0; i <= big; i++)
ways += dp[i];
return ways;
};
int N;
cin >> N;
vector<int> A(N);
for (auto &a : A)
cin >> a;
vector<int> perm(N);
for (int i = 0; i < N; i++)
perm[i] = i;
mod_int answer = 0;
do {
vector<array<int, 2>> ranges;
int extra = 0;
for (int i = N - 1; i >= 0; i--) {
ranges.push_back({1 + extra, A[perm[i]] + extra});
if (i > 0 && perm[i] > perm[i - 1])
extra++;
}
reverse(ranges.begin(), ranges.end());
answer += solve_ranges(ranges) * longest_increasing_subsequence(perm, less<int>());
} while (next_permutation(perm.begin(), perm.end()));
for (int i = 0; i < N; i++)
answer /= A[i];
cout << answer << '\n';
}
Submission Info
| Submission Time |
|
| Task |
E - Random LIS |
| User |
neal |
| Language |
C++ (GCC 9.2.1) |
| Score |
700 |
| Code Size |
14633 Byte |
| Status |
AC |
| Exec Time |
18 ms |
| Memory |
3652 KiB |
Compile Error
./Main.cpp: In function ‘int main()’:
./Main.cpp:439:10: warning: variable ‘solve_ranges_slow’ set but not used [-Wunused-but-set-variable]
439 | auto solve_ranges_slow = [](vector<array<int, 2>> ranges) {
| ^~~~~~~~~~~~~~~~~
./Main.cpp: In instantiation of ‘_m_int<MOD>::_m_int(uint64_t) [with const int& MOD = MOD; uint64_t = long unsigned int]’:
/usr/include/c++/9/bits/stl_construct.h:75:7: required from ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = _m_int<MOD>; _Args = {long unsigned int&}]’
/usr/include/c++/9/bits/stl_uninitialized.h:83:18: required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<long unsigned int*, std::vector<long unsigned int> >; _ForwardIterator = _m_int<MOD>*; bool _TrivialValueTypes = false]’
/usr/include/c++/9/bits/stl_uninitialized.h:140:15: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<long unsigned int*, std::vector<long unsigned int> >; _ForwardIterator = _m_int<MOD>*]’
/usr/include/c++/9/bits/stl_uninitialized.h:307:37: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<long unsigned int*, std::vector<long unsigned int> >; _ForwardIterator = _m_int<MOD>*; _Tp = _m_int<MOD>]’
/usr/include/c++/9/bits/stl_vector.h:1582:33: required from ‘void std::vector<_Tp, _Alloc>::_M_range_initialize(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = __gnu_cxx::__normal_iterator<long unsigned int*, std::vector<long unsigned int> >; _Tp = _m_int<MOD>; _Alloc = std::allocator<_m_int<MOD> >]’
/usr/include/c++/9/bits/stl_vector.h:654:4: required from ‘std::vector<_Tp, _Alloc>::vector(_InputIterator, _InputIter...
Judge Result
| Set Name |
Sample |
All |
| Score / Max Score |
0 / 0 |
700 / 700 |
| Status |
|
|
| Set Name |
Test Cases |
| Sample |
s1.txt, s2.txt, s3.txt |
| All |
01.txt, 02.txt, 03.txt, 04.txt, 05.txt, 06.txt, 07.txt, 08.txt, 09.txt, 10.txt, 11.txt, 12.txt, 13.txt, 14.txt, 15.txt, 16.txt, 17.txt, 18.txt, 19.txt, 20.txt, 21.txt, 22.txt, 23.txt, 24.txt, 25.txt, 26.txt, 27.txt, 28.txt, 29.txt, 30.txt, 31.txt, s1.txt, s2.txt, s3.txt |
| Case Name |
Status |
Exec Time |
Memory |
| 01.txt |
AC |
11 ms |
3624 KiB |
| 02.txt |
AC |
12 ms |
3512 KiB |
| 03.txt |
AC |
4 ms |
3520 KiB |
| 04.txt |
AC |
9 ms |
3456 KiB |
| 05.txt |
AC |
3 ms |
3492 KiB |
| 06.txt |
AC |
17 ms |
3624 KiB |
| 07.txt |
AC |
13 ms |
3436 KiB |
| 08.txt |
AC |
14 ms |
3456 KiB |
| 09.txt |
AC |
8 ms |
3652 KiB |
| 10.txt |
AC |
9 ms |
3548 KiB |
| 11.txt |
AC |
2 ms |
3544 KiB |
| 12.txt |
AC |
5 ms |
3548 KiB |
| 13.txt |
AC |
2 ms |
3436 KiB |
| 14.txt |
AC |
2 ms |
3568 KiB |
| 15.txt |
AC |
2 ms |
3508 KiB |
| 16.txt |
AC |
15 ms |
3496 KiB |
| 17.txt |
AC |
13 ms |
3600 KiB |
| 18.txt |
AC |
14 ms |
3576 KiB |
| 19.txt |
AC |
11 ms |
3572 KiB |
| 20.txt |
AC |
11 ms |
3648 KiB |
| 21.txt |
AC |
18 ms |
3624 KiB |
| 22.txt |
AC |
13 ms |
3576 KiB |
| 23.txt |
AC |
12 ms |
3516 KiB |
| 24.txt |
AC |
12 ms |
3544 KiB |
| 25.txt |
AC |
14 ms |
3620 KiB |
| 26.txt |
AC |
11 ms |
3576 KiB |
| 27.txt |
AC |
14 ms |
3452 KiB |
| 28.txt |
AC |
12 ms |
3460 KiB |
| 29.txt |
AC |
12 ms |
3576 KiB |
| 30.txt |
AC |
13 ms |
3496 KiB |
| 31.txt |
AC |
14 ms |
3544 KiB |
| s1.txt |
AC |
2 ms |
3540 KiB |
| s2.txt |
AC |
2 ms |
3616 KiB |
| s3.txt |
AC |
14 ms |
3440 KiB |