結果
| 問題 |
No.1827 最長部分スーパーリッチ門松列列
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2021-08-15 13:09:03 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.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 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 1 |
| other | AC * 6 TLE * 1 -- * 17 |
ソースコード
#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;
}