結果

問題 No.1827 最長部分スーパーリッチ門松列列
ユーザー maimai
提出日時 2021-08-15 13:09:03
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
TLE  
実行時間 -
コード長 12,596 bytes
コンパイル時間 3,328 ms
コンパイル使用メモリ 205,336 KB
実行使用メモリ 14,592 KB
最終ジャッジ日時 2024-07-21 22:08:25
合計ジャッジ時間 8,765 ms
ジャッジサーバーID
(参考情報)
judge2 / judge4
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
10,752 KB
testcase_01 AC 2 ms
5,376 KB
testcase_02 AC 2 ms
5,376 KB
testcase_03 AC 8 ms
5,376 KB
testcase_04 AC 214 ms
5,376 KB
testcase_05 AC 211 ms
5,376 KB
testcase_06 AC 206 ms
5,376 KB
testcase_07 TLE -
testcase_08 -- -
testcase_09 -- -
testcase_10 -- -
testcase_11 -- -
testcase_12 -- -
testcase_13 -- -
testcase_14 -- -
testcase_15 -- -
testcase_16 -- -
testcase_17 -- -
testcase_18 -- -
testcase_19 -- -
testcase_20 -- -
testcase_21 -- -
testcase_22 -- -
testcase_23 -- -
testcase_24 -- -
権限があれば一括ダウンロードができます

ソースコード

diff #

#pragma GCC optimize("O3")
#include <bits/stdc++.h>

using namespace std;
using ll = long long int;

#define all(v) (v).begin(), (v).end()
#define repeat(cnt, l)                                                         \
  for (typename remove_const<                                                  \
           typename remove_reference<decltype(l)>::type>::type cnt = {};       \
       (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 increase(cnt, b, e) for (auto cnt = (b); (cnt) < (e); ++(cnt))
#define decrease(cnt, b, e) for (auto cnt = (b); (e) <= (cnt); --(cnt))
const long long MD = 1000000007ll;
const long double PI = 3.1415926535897932384626433832795L;
template <typename T1, typename T2>
inline ostream &operator<<(ostream &o, const pair<T1, T2> p) {
  o << '(' << p.first << ':' << p.second << ')';
  return o;
}
template <typename T> inline T &chmax(T &to, const T &val) {
  return to = max(to, val);
}
template <typename T> 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 <typename T, typename Random = decltype(randdev),
          typename enable_if<is_integral<T>::value>::type * = nullptr>
inline T rand(T l, T h, Random &rand = randdev) {
  return uniform_int_distribution<T>(l, h)(rand);
}
template <typename T, typename Random = decltype(randdev),
          typename enable_if<is_floating_point<T>::value>::type * = nullptr>
inline T rand(T l, T h, Random &rand = randdev) {
  return uniform_real_distribution<T>(l, h)(rand);
}
template <typename T>
static ostream &operator<<(ostream &o, const std::vector<T> &v) {
  o << "[ ";
  for (const auto &e : v)
    o << e << ' ';
  return o << ']';
}

template <typename I> struct MyRangeFormat {
  I b, e;
  MyRangeFormat(I _b, I _e) : b(_b), e(_e) {}
};
template <typename I>
static ostream &operator<<(ostream &o, const MyRangeFormat<I> &f) {
  o << "[ ";
  iterate(i, f.b, f.e) o << *i << ' ';
  return o << ']';
}
template <typename I> struct MyMatrixFormat {
  const I &p;
  long long n, m;
  MyMatrixFormat(const I &_p, long long _n, long long _m)
      : p(_p), n(_n), m(_m) {}
};
template <typename I>
static ostream &operator<<(ostream &o, const MyMatrixFormat<I> &f) {
  o << '\n';
  repeat(i, (f.n)) {
    repeat(j, f.m) o << f.p[i][j] << ' ';
    o << '\n';
  }
  return o;
}
struct LOG_t {
  ~LOG_t() { cout << endl; }
};
#define LOG (LOG_t(), cout << 'L' << __LINE__ << ": ")
#define FMTA(m, w) (MyRangeFormat<decltype(m + 0)>(m, m + w))
#define FMTR(b, e) (MyRangeFormat<decltype(e)>(b, e))
#define FMTV(v) FMTR(v.begin(), v.end())
#define FMTM(m, h, w) (MyMatrixFormat<decltype(m + 0)>(m, h, w))

#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
class MaiScanner {
  FILE *fp_;
  constexpr bool isvisiblechar(char c) noexcept {
    return (0x21 <= (c) && (c) <= 0x7E);
  }

public:
  inline MaiScanner(FILE *fp) : fp_(fp) {}
  template <typename T> 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_); }
  template <typename T, typename enable_if<is_integral<T>::value,
                                           nullptr_t>::type = nullptr>
  inline MaiScanner &operator>>(T &var) noexcept {
    input_integer<T>(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 <typename IT> 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 <typename T> 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;
  }
  template <typename T, typename enable_if<is_integral<T>::value,
                                           nullptr_t>::type = nullptr>
  inline MaiPrinter &operator<<(T var) noexcept {
    output_integer<T>(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 <typename IT> 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);

//

class SquareRootDecomposition {
  struct Node {
    int add_;
    shared_ptr<vector<int>> data_;

    int get(int i) const { return data_->operator[](i) + add_; }
    int set(int i, int x) {
      apply();
      return data_->operator[](i) = x;
    }

    void apply() {
      // データが複数のNodeから参照されているならば
      if (data_.use_count() > 1) {
        // O(M)時間で複製する
        data_ = make_shared<vector<int>>(*data_);
      }
      // add_を適用する。
      if (add_ == 0)
        return;
      for (auto &e : *data_)
        e += add_;
      add_ = 0;
    }
    void copyNode(Node &src) {
      add_ = src.add_;
      // note: 参照をコピーするのでO(1)時間で完了する
      data_ = src.data_;
    }
  };

  int M_;
  vector<Node> nodes_;

public:
  SquareRootDecomposition(int sqrtN) : M_(sqrtN), nodes_(sqrtN) {}
  void fill(int x) {
    for (Node &node : nodes_) {
      node.add_ = 0;
      node.data_ = make_shared<vector<int>>(M_, x);
    }
  }
  int getValue(int i) const {
    const auto &node = nodes_[i / M_];
    int x = node.get(i % M_);
    return x;
  }
  void addValueRange(int be, int en, int x) {
    if (be >= en)
      return;
    while (be / M_ * M_ != be) {
      auto &node = nodes_[be / M_];
      node.set(be % M_, node.get(be % M_) + x);
      if (++be >= en)
        return;
    }
    while (be / M_ != en / M_) {
      auto &node = nodes_[be / M_];
      node.add_ += x;
      if ((be += M_) >= en)
        return;
    }
    while (be < en) {
      auto &node = nodes_[be / M_];
      node.set(be % M_, node.get(be % M_) + x);
      ++be;
    }
  }
  void copyValueRange(int be, int en, SquareRootDecomposition &src) {
    if (be >= en)
      return;
    while (be / M_ * M_ != be) {
      auto &node = nodes_[be / M_];
      auto &src_node = src.nodes_[be / M_];
      node.set(be % M_, src_node.get(be % M_));
      if (++be >= en)
        return;
    }
    while (be / M_ != en / M_) {
      auto &node = nodes_[be / M_];
      auto &src_node = src.nodes_[be / M_];
      node.copyNode(src_node);
      if ((be += M_) >= en)
        return;
    }
    while (be < en) {
      auto &node = nodes_[be / M_];
      auto &src_node = src.nodes_[be / M_];
      node.set(be % M_, src_node.get(be % M_));
      ++be;
    }
  }
};

//

struct Problem {
  int N;
  vector<int> A;

  void set(const Problem &p) {
    N = p.N;
    A = p.A;
  }

  void scan() {
    scanner >> N;
    A.resize(N);
    A.shrink_to_fit();
    scanner.in(all(A));
  }

  void generate(int n) {
    N = n;
    A.resize(N);
    A.shrink_to_fit();
    iota(all(A), 1);
    shuffle(all(A), randdev);
  }

  virtual int solve() { return -1; };
};

//

struct ProblemSolverExp : public Problem {
  int solve() override {
    if (N > 24)
      return -1;

    int best_len = 1;
    // 全列挙
    for (int b = 1; b < (1 << N); ++b) {
      // ビット列から部分列を生成
      vector<int> aa;
      repeat(i, N) if (b & (1 << i)) aa.push_back(A[i]);
      if (aa.size() <= 1)
        continue;

      // 評価
      int even_min = numeric_limits<int>::max();
      int odd_max = 0;
      int even_max = 0;
      int odd_min = numeric_limits<int>::max();
      repeat(j, int(aa.size())) {
        if (j & 1) {
          chmin(odd_min, aa[j]);
          chmax(odd_max, aa[j]);
        } else {
          chmin(even_min, aa[j]);
          chmax(even_max, aa[j]);
        }
      }
      if (even_max < odd_min || odd_max < even_min)
        chmax<int>(best_len, aa.size());
    }
    return best_len;
  }
};

//

struct ProblemSolverN2 : public Problem {
private:
  int greedy(int t) {
    // 偶数/奇数要素がt+0.5未満/以上となるように貪欲で選ぶ
    // この貪欲な選び方はtを固定した上では最適
    int best_len = 0;
    repeat(updown, 2) {
      int len = 0;
      bool odd = updown;
      repeat(i, N) {
        if (odd) {
          if (t < A[i]) {
            odd = !odd;
            len += 1;
          }
        } else {
          if (t >= A[i]) {
            odd = !odd;
            len += 1;
          }
        }
      }
      chmax(best_len, len);
    }
    return best_len;
  }

public:
  int solve() override {
    if (N > 6000)
      return -1;

    int best_len = 1;
    repeat(i, N - 1) {
      // 境界値をi+1.5として選ぶ
      // 境界値を元に貪欲に決定
      int l = greedy(i + 1);
      chmax(best_len, l);
    }
    return best_len;
  }
};

//

struct ProblemSolverN2a : public Problem {
  int solve() override {
    if (N > 6000)
      return -1;

    vector<int> vec_down(N); // i+0.5 を境界としている
    vector<int> vec_up(N);

    repeat(i, N) {
      int a = A[i] - 1;
      for (int x = 0; x <= a; ++x) {
        // chmax(vec_up[x], vec_down[x] + 1);
        vec_up[x] = vec_down[x] + 1;
      }
      for (int x = a + 1; x < N; ++x) {
        vec_down[x] = vec_up[x] + 1;
      }
      // 区間のコピーが必要!!
      // 区間の位置が変わらないコピーなので、平方分割が使える。
    }
    int best_len = 1;
    repeat(i, N) chmax(best_len, vec_up[i]);
    repeat(i, N) chmax(best_len, vec_down[i]);
    return best_len;
  }
};

struct ProblemSolverNq : public Problem {
  int solve() override {

    int m = max(3, int(sqrt(N)) + 1);
    SquareRootDecomposition vec_down(m); // i+0.5 を境界としている
    SquareRootDecomposition vec_up(m);
    vec_down.fill(0);
    vec_up.fill(0);

    repeat(i, N) {
      int a = A[i] - 1;
      {
        vec_up.copyValueRange(0, a + 1, vec_down);
        vec_up.addValueRange(0, a + 1, 1);
      }
      {
        vec_down.copyValueRange(a + 1, N, vec_up);
        vec_down.addValueRange(a + 1, N, 1);
      }
    }
    int best_len = 1;
    repeat(i, N) chmax(best_len, vec_up.getValue(i));
    repeat(i, N) chmax(best_len, vec_down.getValue(i));
    return best_len;
  }
};

//

//

void test1() {
  Problem p;
  p.N = 8;
  p.A.resize(p.N);
  iota(all(p.A), 1);
  do {

    ProblemSolverExp p1;
    ProblemSolverN2 p2;
    ProblemSolverN2a p3;
    ProblemSolverNq p4;
    p1.set(p);
    p2.set(p);
    p3.set(p);
    p4.set(p);

    int a1 = p1.solve();
    int a2 = p2.solve();
    int a3 = p3.solve();
    int a4 = p4.solve();
    if (a1 != a2 || a2 != a3 || a3 != a4) {
      LOG << p.A;
      LOG << a1 << " " << a2 << " " << a3 << " " << a4;
      break;
    }

  } while (next_permutation(all(p.A)));
  LOG << "done";
}

void test2() {
  Problem p;
  p.N = 100;
  p.A.resize(p.N);
  iota(all(p.A), 1);
  repeat(_, 1000) {
    shuffle(all(p.A), randdev);

    ProblemSolverN2 p2;
    ProblemSolverNq p4;
    p2.set(p);
    p4.set(p);

    int a2 = p2.solve();
    int a4 = p4.solve();
    if (a2 != a4) {
      LOG << p.A;
      LOG << a2 << " " << a4;
      break;
    }
  }
  LOG << "done";
}

void single() {
  // ProblemSolverN2a p;
  ProblemSolverNq p;

  int T;
  scanner >> T;
  repeat(i, T) {
    p.scan();
    printer << p.solve() << '\n';
  }
}

int main() {

  single();
  // test2();

  return 0;
}
0