#include #include #include #include #include #include #include #include #include #include #include template class LazyPtr { public: template T& operator()(Args... args) { if(!init)new (_buf)T(args...); init = true; return **this;} T* operator->() { return ((T*)_buf); } T& operator*() { return *((T*)_buf); } private: bool init = false; char _buf[sizeof(T)]; }; #ifdef _MSC_VER #include inline int CLZ(int n){unsigned long ret; _BitScanForward(&ret, n); return ret;} //inline int CLZ(long long int n){unsigned long ret; _BitScanForward64(&ret, n); return ret;} inline int CTZ(int n){unsigned long ret; _BitScanReverse( &ret, n); return 31 - ret;} //inline int CTZ(long long int n){unsigned long ret; _BitScanReverse64( &ret, n); return 63 - ret;} inline int POPCNT(int n){return __popcnt(n);} //inline int POPCNT(long long int n){return __popcnt64(n);} #endif #ifdef __GNUC__ inline int CLZ(int n){return __builtin_clz(n);} inline int CLZLL(long long int n){return __builtin_clzll(n);} inline int CTZ(int n){return __builtin_ctz(n);} inline int CTZLL(long long int n){return __builtin_ctzll(n);} inline int POPCNT(int n){return __builtin_popcount(n);} inline int POPCNTLL(long long int n){return __builtin_popcountll(n);} #endif template struct ScanfSpecifier{}; #define DEF(T,V) template<> struct ScanfSpecifier{static constexpr const char* value = V;}; DEF(char*,"%s")DEF(int,"%d")DEF(double,"%lf")DEF(float,"%f")DEF(char,"%c")DEF(const char*,"%s")DEF(unsigned long,"%lu")DEF(unsigned int, "%u") #ifdef _MSC_VER DEF(long long int,"%I64d") #else DEF(long long int,"%lld") #endif #undef DEF template int RD(T& arg){return std::scanf(ScanfSpecifier::value, &arg);} template int RD(char (&arg)[S]){return std::scanf("%s", arg);} int RD(char* arg){return std::scanf("%s", arg);} template<> int RD(char& arg){return std::scanf(" %c", &arg);} template int RD(T& arg1, Args&... args) {return RD(arg1) + RD(args...);} template T RD(){T ret; RD(ret); return ret;} template void RDV(It begin, It end) { while(begin != end) RD(*begin++); } template void RDV(C& c) {RDV(std::begin(c), std::end(c));} template void WT(T arg) {std::printf(ScanfSpecifier::value, arg); } template void WT(std::pair arg) {std::printf("("); WT(arg.first); std::printf(", "); WT(arg.second); std::printf(")");} template void WT(Args... args) { int alc = 0; int dummy[] = {((alc++? std::printf(" "): 0), WT(args), 0)...}; } template void WTL(Args... args) { WT(args...); std::printf("\n"); } template void WTV(It begin, It end) { int alc = 0; while(begin != end) (alc++? std::printf(" "): 0), WT(*begin++); } template void WTV(const C& c) {WTV(std::begin(c), std::end(c));} template void WTVL(It begin, It end) { WTV(begin, end); std::printf("\n"); } template void WTVL(const C& c) {WTVL(std::begin(c), std::end(c));} namespace XX { struct BlockManager { void* alloc() { void* ret; if(_ptr) { ret = _ptr; _ptr = *static_cast(_ptr); } else { if(_pos == _size) { _pos = 0; _buf[++_idx] = new char[_size <<= 1]; } ret = _buf[_idx] + _pos; _pos += blocksize; } return ret; } void dealloc(void* p) { *static_cast(p) = _ptr; _ptr = p; } ~BlockManager() { for(int i = 0; i <= _idx; i++) delete []_buf[i]; } int blocksize; BlockManager(int b): blocksize(b), _size(std::max(1, 128 * 128 / blocksize) * blocksize), _pos(_size) {} int _size; int _idx = -1; int _pos; char* _buf[32] = {}; void* _ptr = nullptr; }; class BufferManager { public: static BufferManager* inst() { static BufferManager ret; return &ret; } static int fitting(int len) { return 31 - CLZ(len) + !!(len & (len - 1)); } void* alloc(int len) { int logn = fitting(len); return this->block[logn](1 << logn).alloc(); } void dealloc(void* p, int len) { int logn = fitting(len); this->block[logn](1 << logn).dealloc(p); } private: LazyPtr block[32]; }; template struct Buffer { using BM = BufferManager; Buffer(): Buffer(0){} template::value_type> Buffer(It b, It e): Buffer(std::distance(b, e)) {std::copy(b, e, _ptr);} Buffer(int size){alloc(std::max(R, size));} template Buffer(int size, U value):Buffer(size) { std::fill(_ptr, _ptr + _size, value); } Buffer(const Buffer& other){assign(other);} Buffer(Buffer&& other){take(other);} template Buffer(const Buffer& other){assign(other);} template Buffer(Buffer&& other){take(other);} Buffer& operator=(const Buffer& other){assign(other); return *this;} Buffer& operator=(Buffer&& other){take(other); return *this;} template Buffer& operator=(const Buffer& other){assign(other); return *this;} template Buffer& operator=(Buffer&& other){take(other); return *this;} ~Buffer(){dealloc();} void dealloc() { if(_ptr)BM::inst()->dealloc(_ptr, _realsize * sizeof(T)), _ptr = nullptr; } void resize(int size) { if(size > _realsize) { auto old_ptr = _ptr; auto old_size = _size; int old_realsize = _realsize; alloc(size); std::copy(old_ptr, old_ptr + old_size, _ptr); if(old_ptr) BM::inst()->dealloc(old_ptr, sizeof(T) * old_realsize); } _size = size; } template void resize(int size, U value) { int old_size = _size; resize(size); if(old_size < size) std::fill(_ptr + old_size, _ptr + size, value); } template void take(Buffer& other) { dealloc(); _realsize = other._realsize; _size = other._size; _ptr = other._ptr; other._ptr = nullptr; } void push_back(T value) { resize(_size + 1); _ptr[_size - 1] = value; } void pop_back() { resize(_size - 1); } void alloc(int size) { _size = size; _realsize = (size? 1 << BM::fitting(size * sizeof(T)): 0) / sizeof(T); _ptr = size? static_cast(BM::inst()->alloc(size * sizeof(T))): nullptr; } template void assign(const Buffer& other) { if(_realsize < other._size) { dealloc(); alloc(other._size); } _size = other._size; std::copy(other.begin(), other.end(), begin()); } int size()const{return _size;} T& back(int idx = 0){return _ptr[_size - 1 - idx];} const T& back(int idx = 0)const{return _ptr[_size - 1 - idx];} T& operator[](int idx){return _ptr[idx];} const T& operator[](int idx)const{return _ptr[idx];} T* begin()const{return _ptr;} T* end()const{return _ptr + _size;} int _size = 0; int _realsize = 0; T* _ptr = nullptr; }; } template struct Mapper { int operator[](const T& v) { int& ret = table[v]; if(!ret) rtable[ret = table.size()] = v; return ret - 1; } template int operator()(Args... args) { return (*this)[T(args...)]; } T rev(int idx){return rtable[idx + 1];} std::map table; std::map rtable; }; template struct ReferenceArray { struct It {typename std::array::iterator it; T& operator*(){return **it;} void operator++(){it++;} bool operator!=(const It& other){return it != other.it;} }; int size()const{return _ptr.size();} It begin()const{return {_ptr.begin()};} It end()const{return {_ptr.end()};} T& operator[](int idx)const{return *_ptr[idx];} mutable std::array _ptr; }; template ReferenceArray MAKEV(T& arg1, Args&... args) {return {&arg1, &args...};} struct Range { struct It { int num, step; int operator*(){return num;} void operator++(){num += step;} bool operator!=(const It& other){return num != other.num;} }; Range(int ee):b(0),e(ee){} Range(int bb, int ee):b(bb), e(ee){} It begin(){return {b, (b < e? 1: -1)};} It end(){return {e, 0};} int b, e; }; template inline T& UMAX(T& x, T y){if(x < y)x = y; return x;} template inline T& UMIN(T& x, T y){if(y < x)x = y; return x;} template struct ArithmiticPromotion { typedef decltype(T() + typename ArithmiticPromotion::type()) type; }; template struct ArithmiticPromotion { typedef decltype(T() + U()) type; }; template struct ArithmiticPromotion { typedef T type; }; template struct ArithmiticPromotion { typedef T type; }; template typename ArithmiticPromotion::type MAX(T a, U b) { return a < b? b: a; } template typename ArithmiticPromotion::type MAX(T a, Args... args) { return MAX(a, MAX(args...)); } template typename ArithmiticPromotion::type MIN(T a, U b) { return a < b? a: b; } template typename ArithmiticPromotion::type MIN(T a, Args... args) { return MIN(a, MIN(args...)); } namespace XX { template class FactorialTable { public: FactorialTable() { table[0] = 1; for(int i = 1; i <= D; i++) table[i] = table[i - 1] * i; } T operator[](int x) {return table[x];} private: T table[D + 1]; }; template T factorial(int x) { static FactorialTable table; return table[x]; } template class InverseFactorialTable { public: InverseFactorialTable() { table[D] = T(1) / factorial(D); for(int i = D - 1; i >= 0; i--) table[i] = table[i + 1] * (i + 1); } T operator[](int x) {return table[x];} private: T table[D + 1]; }; template T inversefactorial(int x) { static InverseFactorialTable table; return table[x]; } template T binomialCoefficient(int n, int k) { return factorial(n) * inversefactorial(n - k) * inversefactorial(k); } template class BinomialTable { public: BinomialTable() { for(int i = 0; i <= D; i++) { table[i][i] = table[i][0] = T(1); for(int j = 1; j < i; j++) table[i][j] = table[i - 1][j] + table[i - 1][j - 1]; } } T operator()(int x, int y) { return table[x][y]; } private: T table[D + 1][D + 1] = {}; }; } template struct ZpZ { static const unsigned int P = Z; using U64 = unsigned long long int; U64 value; ZpZ(long long int n) {if(std::abs(n) >= P)n %= P; if(n < 0)n += P; value = n;} ZpZ():value(0){} ZpZ& operator+=(ZpZ p){if((value += p.value) >= P)value -= P; return *this;} ZpZ& operator-=(ZpZ p){if(value >= p.value)value -= p.value; else value += P - p.value; return *this;} ZpZ& operator*=(ZpZ p){value = value * p.value % P; return *this;} ZpZ& operator/=(ZpZ p){value = value * p.inverse().value % P; return *this;} bool operator==(ZpZ p){return value == p.value;} bool operator!=(ZpZ p){return value != p.value;} #define DEF(op) ZpZ operator op(ZpZ r)const{return ZpZ(value) op##= r;} DEF(+)DEF(-)DEF(*)DEF(/) #undef DEF explicit operator long long int()const{return value;} explicit operator int()const{return value;} ZpZ operator-(){return P - value;} ZpZ inverse() { int a = value, b = P, u = 1, v = 0; while(b) { int t = a / b; std::swap(a -= t * b, b); std::swap(u -= t * v, v); } if(u < 0) u += P; return u; } ZpZ pow(U64 e) { U64 ret = 1, base = value; while(e) { if((e & 1) && ((ret *= base) >> 32)) ret %= P; if((base *= base) >> 32) base %= P; e >>= 1; } return ret; } }; template void WT(ZpZ

arg) {WT((int)arg);} namespace XX { namespace FFT { const double PI = std::acos(-1.0); template struct Complex { typedef CT value_type; CT real, imag; Complex& operator=(CT v){real = v, imag = 0; return *this;} void operator/=(double l) { real /= l; imag /= l; } void operator*=(double l) {real *= l, imag *= l; } template T toInt() { return T(real + 0.5); } explicit operator int(){return toInt();} explicit operator long long(){return toInt();} }; template inline Complex operator+(const Complex& a, const Complex& b) { return {a.real + b.real, a.imag + b.imag}; } template inline Complex operator-(const Complex& a, const Complex& b) { return {a.real - b.real, a.imag - b.imag}; } template inline Complex operator*(const Complex& a, const Complex& b) { return {a.real * b.real - a.imag * b.imag, a.real * b.imag + a.imag * b.real}; } template inline Complex conj(const Complex& a) { return {a.real, -a.imag}; } std::vector revpos; int fittingLength(int len) { if(len & (len - 1)) return 1 << (31 - CLZ(len) + 1); else return std::max(2, len); } template const std::vector>& getRoot(int len) { static std::vector> root; if((int)root.size() < len * 2) { int oldk = root.size(); root.resize(len * 2); root[1] = {1, 0}; for(int k = std::max(2, oldk); k < (len << 1); k <<= 1) { Complex m = {CT(std::cos(2 * PI / (k))), CT(std::sin(2 * PI / (k)))}; for(int i = k >> 1; i < k; i++) { root[2 * i] = root[i]; root[2 * i + 1] = root[i] * m; } } } return root; } template void inplace(It begin, It end, bool inverse = false) { using CT = typename std::remove_reference::type::value_type; int len = fittingLength(std::distance(begin, end)); int logn = (31 - CLZ(len)); if((int)revpos.size() != len) { revpos.resize(len); for(int i = 0; i < len; i++) revpos[i] = (revpos[i >> 1] >> 1) + ((i & 1) << (logn - 1)); } auto& root = getRoot(len); for(int i = 1; i < len; i++) if(i < revpos[i]) std::swap(begin[i], begin[revpos[i]]); for(int i = 0, l = 1, ll = 2; l < len; i++, l <<= 1, ll <<= 1) for(int j = 0; j < len; j += 1 << (i + 1)) for(int k = j; k < j + l; k++) { Complex a = begin[k], b = (inverse? conj(root[ll + k - j]): root[ll + k - j]) * begin[k + l]; begin[k] = a + b; begin[k + l] = a - b; } if(inverse) for(int i = 0; i < len; i++) begin[i] /= len; } template std::vector> fft(It begin, It end, bool inverse = false, int extend = 0) { int len = fittingLength(extend? extend: std::distance(begin, end)); std::vector> ret(len); std::copy(begin, end, ret.begin()); inplace(ret.begin(), ret.end(), inverse); return ret; } template void inplace_unary(It beg, int deg, CT coef, int extend = 0) { int len = fittingLength(extend? extend: deg + 1); auto& root = getRoot(len); for(int i = 0, p = 0; i < len; i++, p = (p + deg) & (len - 1)) (beg[i] = root[len + p]) *= coef; } template std::vector> fft_unary(int deg, CT coef, int extend = 0) { int len = fittingLength(extend? extend: deg + 1); std::vector> ret(len); inplace_unary(ret.begin(), deg, coef, extend); return ret; } template std::vector> convolution(It b1, It e1, It b2, It e2) { int N = std::distance(b1, e1); int M = std::distance(b2, e2); std::vector> v(fittingLength(N + M - 1)); for(int i = 0, j = std::max(N, M); i < j; i++) v[i] = {i < N? CT(b1[i]): 0, i < M? CT(b2[i]): 0}; inplace(v.begin(), v.end()); for(int i = 0, k = v.size() >> 1; i <= k; i++) { int j = (v.size() - i) & (v.size() - 1); CT a = v[i].real + v[j].real, b = v[i].imag - v[j].imag, c = v[i].imag + v[j].imag, d = v[j].real - v[i].real; v[j] = conj(v[i] = {(a * c - b * d) / 4, (a * d + b * c) / 4}); } inplace(v.begin(), v.end(), true); return v; } template Buffer convolutionMod(It b1, It e1, It b2, It e2, int mod) { int N = std::distance(b1, e1); int M = std::distance(b2, e2); int L = fittingLength(N + M - 1); Buffer> v1(L, 0), v2(L, 0); // std::vector> v1(L), v2(L); for(int i = 0; i < N; i++) v1[i] = {CT((long long)b1[i] & ((1 << 15) - 1)), CT((long long)b1[i] >> 15)}; for(int i = 0; i < M; i++) v2[i] = {CT((long long)b2[i] & ((1 << 15) - 1)), CT((long long)b2[i] >> 15)}; inplace(v1.begin(), v1.end()); inplace(v2.begin(), v2.end()); CT d = CT(1) / (L << 1); for(int i = 0, k = L >> 1; i <= k; i++) { int j = (L - i) & (L - 1); Complex a1 = {(v1[i].real + v1[j].real) * 0.5, (v1[i].imag - v1[j].imag) * 0.5}, b1 = {(v1[i].imag + v1[j].imag) * 0.5, (v1[j].real - v1[i].real) * 0.5}; Complex a2 = {(v2[i].real + v2[j].real) * d, (v2[i].imag - v2[j].imag) * d}, b2 = {(v2[i].imag + v2[j].imag) * d, (v2[j].real - v2[i].real) * d}; auto x = a1 * a2; auto y = b1 * b2 * Complex{0, 1}; v1[j] = x + y; v1[i] = Complex{x.real + -y.real, y.imag - x.imag}; v2[j] = a1 * b2 + b1 * a2; v2[i] = conj(v2[j]); } inplace(v1.begin(), v1.end()); inplace(v2.begin(), v2.end()); Buffer ret(L); long double mx = 0; for(int i = 0; i < L; i++) { long long int l = v1[i].real + 0.5, m = v2[i].real + 0.5, h = v1[i].imag + 0.5; ret[i] = (l + (m % mod << 15) + (h % mod << 30)) % mod; } return ret; } } } #define MYLIB_TEST //alias //RD[L],RDV[L],WT[L],WTV[L] for i/o const int SIZE = 1234; const int MOD = 1e9 + 7; using ZZ = ZpZ; ZZ min(ZZ a, ZZ b){return std::min(a.value, b.value);} ZZ max(ZZ a, ZZ b){return std::max(a.value, b.value);} using RG = Range; //bit operation => CLZ,CTZ,POPCNT using XX::FFT::Complex; using XX::FFT::inplace; using XX::FFT::fft; using XX::FFT::convolution; using XX::FFT::convolutionMod; auto fact = XX::factorial; auto ifact = XX::inversefactorial; //auto bc = XX::binomialCoefficient; //auto bc = XX::BinomialTable(); //template #include #include #include #include #include #include #include #include using namespace std; typedef long long int ll; ll dp[SIZE * 2][SIZE]; int A[SIZE]; ll invf[SIZE]; int main() { for(int i: RG(SIZE)) invf[i] = (ll)ifact(i); int N; RD(N); RDV(A + 1, A + N + 1); A[0] = 5678; for(int i = 1; i <= N; i++) dp[i][0] = (ll)fact(i); for(int last, i = 1; i <= N; i++) { if(A[i - 1] > A[i]) last = i - 1; auto res = convolutionMod(dp[i] + last, dp[i] + i, invf, invf + SIZE, MOD); for(int j = 0; j < N; j++) if(i - last - j >= 0) dp[i + j][i] = (ll)(fact(j) * res[i - last - j]); } WTL(dp[N][N]); }