#pragma GCC optimize ("O3") #include "bits/stdc++.h" using namespace std; using ll = long long int; #define debugos cout #define debug(v) {printf("L%d %s > ",__LINE__,#v);debugos<<(v)< ",__LINE__,#v);for(auto e:(v)){debugos< ",__LINE__,#m);for(int x=0;x<(w);x++){debugos<<(m)[x]<<" ";}debugos<\n",__LINE__,#m);for(int y=0;y<(h);y++){for(int x=0;x<(w);x++){debugos<<(m)[y][x]<<" ";}debugos<::type();(cnt)<(l);++(cnt)) #define rrepeat(cnt,l) for(auto cnt=(l)-1;0<=(cnt);--(cnt)) #define iterate(cnt,b,e) for(auto cnt=(b);(cnt)!=(e);++(cnt)) #define diterate(cnt,b,e) for(auto cnt=(b);(cnt)!=(e);--(cnt)) const ll MD = 1000000007ll; const long double PI = 3.1415926535897932384626433832795L; inline void assert_call(bool assertion, function f) { if (!assertion) { cerr << "assertion fault:" << endl; f(); abort(); } } template inline ostream& operator <<(ostream &o, const pair p) { o << '(' << p.first << ':' << p.second << ')'; return o; } template inline ostream& _ostream_vecprint(ostream& os, const Vec& a) { os << '['; for (const auto& e : a) os << ' ' << e << ' '; os << ']'; return os; } template inline ostream& operator<<(ostream& o, const vector& v) { return _ostream_vecprint(o, v); } template inline ostream& operator<<(ostream& o, const array& v) { return _ostream_vecprint(o, v); } template inline T& chmax(T& to, const T& val) { return to = max(to, val); } template inline T& chmin(T& to, const T& val) { return to = min(to, val); } void bye(string s, int code = 0) { cout << s << endl; exit(code); } mt19937_64 randdev(8901016); template::value>::type* = nullptr> inline T rand(T l, T h, Random& rand = randdev) { return uniform_int_distribution(l, h)(rand); } template::value>::type* = nullptr> inline T rand(T l, T h, Random& rand = randdev) { return uniform_real_distribution(l, h)(rand); } #if defined(_WIN32) || defined(_WIN64) #define getc_x _getc_nolock #define putc_x _putc_nolock #elif defined(__GNUC__) #define getc_x getc_unlocked #define putc_x putc_unlocked #else #define getc_x getc #define putc_x putc #endif #define isvisiblechar(c) (0x21<=(c)&&(c)<=0x7E) class MaiScanner { FILE* fp_; public: inline MaiScanner(FILE* fp):fp_(fp){} template void input_integer(T& var) noexcept { var = 0; T sign = 1; int cc = getc_x(fp_); for (; cc < '0' || '9' < cc; cc = getc_x(fp_)) if (cc == '-') sign = -1; for (; '0' <= cc && cc <= '9'; cc = getc_x(fp_)) var = (var << 3) + (var << 1) + cc - '0'; var = var * sign; } inline int c() noexcept { return getc_x(fp_); } inline MaiScanner& operator>>(int& var) noexcept { input_integer(var); return *this; } inline MaiScanner& operator>>(long long& var) noexcept { input_integer(var); return *this; } inline MaiScanner& operator>>(string& var) { int cc = getc_x(fp_); for (; !isvisiblechar(cc); cc = getc_x(fp_)); for (; isvisiblechar(cc); cc = getc_x(fp_)) var.push_back(cc); return *this; } template inline void in(IT begin, IT end) { for (auto it = begin; it != end; ++it) *this >> *it; } }; class MaiPrinter { FILE* fp_; public: inline MaiPrinter(FILE* fp):fp_(fp){} template void output_integer(T var) noexcept { if (var == 0) { putc_x('0', fp_); return; } if (var < 0) putc_x('-', fp_), var = -var; char stack[32]; int stack_p = 0; while (var) stack[stack_p++] = '0' + (var % 10), var /= 10; while (stack_p) putc_x(stack[--stack_p], fp_); } inline MaiPrinter& operator<<(char c) noexcept { putc_x(c, fp_); return *this; } inline MaiPrinter& operator<<(int var) noexcept { output_integer(var); return *this; } inline MaiPrinter& operator<<(long long var) noexcept { output_integer(var); return *this; } inline MaiPrinter& operator<<(char* str_p) noexcept { while (*str_p) putc_x(*(str_p++), fp_); return *this; } inline MaiPrinter& operator<<(const string& str) { const char* p = str.c_str(); const char* l = p + str.size(); while (p < l) putc_x(*p++, fp_); return *this; } template void join(IT begin, IT end, char sep = ' ') { for (bool b = 0; begin != end; ++begin, b = 1) b ? *this << sep << *begin : *this << *begin; } }; MaiScanner scanner(stdin); MaiPrinter printer(stdout); template class Bitree { const int size_; vector data_; static int nlz(uint32_t x) { union { uint32_t i; float f; } data; data.f = (float)x + 0.5; return 158 - (data.i >> 23); } public: Bitree(int size_) :size_(size_), data_(size_+1) {} // 1..rの範囲の値の和を求める. T sum(int r) const { T s = 0; while (r) { s += data_[r]; r -= r&-r; // r&-r と書くことで最下のビットを得る } return s; } // l..rの範囲の値の和を求める inline T sum(int l, int r) const { return sum(r) - sum(l-1); } // i番目の値を求める(1index) T get(int i) const { int j = i - 1; T s = 0; while (i != j) { s += data_[i] - data_[j]; i -= i&-i; j -= j&-j; } return s; } // idxの要素の値をval増やす void add(int idx, T val) { while (idx <= size_) { data_[idx] += val; idx += idx&-idx; } } // sum(i)がvalを超える最初のiを返す // get(j)<0となるjが存在すると正しく動作しない int upper_bound(T val) const { int li = 1 << (31 - nlz(size_)); int p = 0; T d = 0; while (li && p < size_) { T k = data_[p | li]; if (!(val < d + k)) p |= li, d += k; li >>= 1; } if (p > size_) p = size_; return p+1; } // sum(i)がvalを超えるである最初のiを返す // get(j)<0となるjが存在すると正しく動作しない int lower_bound(T val) const { int li = 1 << (31 - nlz(size_)); int p = 0; T d = 0; while (li && p < size_) { T k = data_[p | li]; if (d + k < val) p |= li, d += k; li >>= 1; } if (p > size_) p = size_; return p+1; } }; // int N; int _A[200010]; int * const A = _A+1; // constexpr bool iskado(int a, int b, int c) noexcept { return a != c && ((a < b && b > c) || (a > b && b < c)); } void input() { scanner >> N; scanner.in(A, A+N); } void generate() { static mt19937 devicemt; map mp; int watcher = 0; repeat(i, N) { if (++watcher > 9999999) { generate(); return; } auto x = static_cast(devicemt()); if (1 < i && !iskado(A[i-2], A[i-1], x)) { --i; continue; } auto& r = mp[x]; if (r) { --i; continue; } r = 1; A[i] = x; } int idx = 0; for (auto& p : mp) { p.second = ++idx; } repeat(i, N) { A[i] = mp[A[i]]; } repeat(v, N-2) { if (!iskado(A[v], A[v+1], A[v+2])) { cout << "generator fault" << endl; debuga(A, N); abort(); } } } ll solve1() { ll ans = 0; iterate(i, 0, N-1) { iterate(j, i+1, N) { swap(A[i], A[j]); bool ok = true; repeat(v, N-2) { if (!iskado(A[v], A[v+1], A[v+2])) { ok = false; break; } } // if (ok) debug(make_pair(i, j)); ans += ok; swap(A[i], A[j]); } } return ans; } ll solve2() { if (A[N-2] < A[N-1]) A[N] = 0; else A[N] = N+1; if (A[0] < A[1]) A[-1] = N+2; else A[-1] = -1; vector> downs, ups; repeat(i, N) { if (A[i] < A[i+1]) { // でこ // この場所はbound未満の値を入れないとダメ int bound = min(A[i-1], A[i+1]); downs.emplace_back(A[i], bound); } else{ // ぼこ // この場所はboundを超える値を入れないとダメ int bound = max(A[i-1], A[i+1]); ups.emplace_back(A[i], bound); } } vector> queriesLL, queriesLH, queriesHL, queriesHH; repeat(i, N) { if (A[i] < A[i+1]) { // この場所はbound未満の値を入れないとダメ int bound = min(A[i-1], A[i+1]); // 交換する値がbound未満の値で、かつ、交換先がぼこのA[i]未満より緩い制約すなわちA[i]を超える queriesLH.emplace_back(bound, A[i]); // 交換する値がbound未満の値で、かつ、交換先がでこのA[i]を超えるより緩い制約すなわちA[i]未満 queriesLL.emplace_back(bound, A[i]); } else{ // この場所はboundを超える値を入れないとダメ int bound = max(A[i-1], A[i+1]); // 交換する値がboundを超える値で、かつ、交換先がぼこA[i]未満より緩い制約すなわちA[i]を超える queriesHH.emplace_back(bound, A[i]); // 交換する値がboundを超える値で、かつ、交換先がでこA[i]を超えるより緩い制約すなわちA[i]未満 queriesHL.emplace_back(bound, A[i]); } } ll total = 0; { // 凹凹 vector, bool>> acts; for (auto p : downs) acts.emplace_back(make_pair(p.first, -p.second), true); for (auto p : queriesLH) acts.emplace_back(make_pair(p.first, -p.second), false); sort(all(acts)); Bitree bit(N+1); for (auto act : acts) { if (act.second) { // second未満の値を入れないとダメな、値firstの場所 // debug(act.first); bit.add(-act.first.second, 1); } else{ // debug(act.first); // debug(bit.sum(-act.first.second, N)); // first以下の値で、交換先がsecond以下と同等かよりゆるい制約すなわち制約境界値がsecond以上 total += bit.sum(-act.first.second, N); } } } { // 凸凹 vector, bool>> acts; for (auto p : ups) acts.emplace_back(make_pair(p.first, p.second), true); for (auto p : queriesLL) acts.emplace_back(make_pair(p.first, p.second), false); sort(all(acts)); Bitree bit(N+1); for (auto act : acts) { if (act.second) { // secondを超える値を入れないとダメな、値firstの場所 // debug(act.first); bit.add(act.first.second, 1); } else{ // debug(act.first); // debug(bit.sum(act.first.second)); // first以下の値で、交換先がsecondを超えるよりゆるい制約すなわち制約がsecond未満 total += bit.sum(act.first.second); } } } { // 凹凸 vector, bool>> acts; for (auto p : downs) acts.emplace_back(make_pair(-p.first, -p.second), true); for (auto p : queriesHH) acts.emplace_back(make_pair(-p.first, -p.second), false); sort(all(acts)); Bitree bit(N+1); for (auto act : acts) { if (act.second) { // debug(act.first); bit.add(-act.first.second, 1); } else{ // debug(act.first); // debug(bit.sum(-act.first.second, N)); total += bit.sum(-act.first.second, N); } } } { // 凹凹 vector, bool>> acts; for (auto p : ups) acts.emplace_back(make_pair(-p.first, p.second), true); for (auto p : queriesHL) acts.emplace_back(make_pair(-p.first, p.second), false); sort(all(acts)); Bitree bit(N+1); for (auto act : acts) { if (act.second) { // secondを超える値を入れないとダメな、値firstの場所 // debug(act.first); bit.add(act.first.second, 1); } else{ // // debug(act.first); // debug(bit.sum(act.first.second)); total += bit.sum(act.first.second); } } } // debug(total); return (total - N) / 2; } int main_test() { N = 100; repeat(_, 10000) { generate(); auto a1 = solve1(); auto a2 = solve2(); if (a1 != a2) { cout << _ << endl; debuga(A, N); cout << a1 << endl << a2 << endl; abort(); } } cout << "AC" << endl; return 0; } int main() { input(); // cout << solve1() << endl; cout << solve2() << endl; return 0; }