結果

問題 No.2454 Former < Latter
ユーザー tokusakuraitokusakurai
提出日時 2023-09-01 22:06:17
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 101 ms / 2,000 ms
コード長 20,075 bytes
コンパイル時間 2,936 ms
コンパイル使用メモリ 219,188 KB
実行使用メモリ 17,336 KB
最終ジャッジ日時 2023-09-01 22:06:23
合計ジャッジ時間 4,827 ms
ジャッジサーバーID
(参考情報)
judge16 / judge11
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,380 KB
testcase_01 AC 1 ms
4,380 KB
testcase_02 AC 46 ms
15,088 KB
testcase_03 AC 40 ms
15,100 KB
testcase_04 AC 43 ms
15,548 KB
testcase_05 AC 54 ms
15,628 KB
testcase_06 AC 55 ms
15,428 KB
testcase_07 AC 41 ms
15,148 KB
testcase_08 AC 37 ms
4,376 KB
testcase_09 AC 26 ms
6,756 KB
testcase_10 AC 29 ms
7,116 KB
testcase_11 AC 40 ms
15,032 KB
testcase_12 AC 47 ms
15,020 KB
testcase_13 AC 20 ms
15,112 KB
testcase_14 AC 20 ms
15,032 KB
testcase_15 AC 50 ms
10,396 KB
testcase_16 AC 45 ms
10,224 KB
testcase_17 AC 101 ms
4,380 KB
testcase_18 AC 46 ms
4,376 KB
testcase_19 AC 52 ms
17,336 KB
testcase_20 AC 67 ms
16,252 KB
testcase_21 AC 40 ms
4,376 KB
testcase_22 AC 33 ms
5,928 KB
testcase_23 AC 35 ms
7,104 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (n); i++)
#define per(i, n) for (int i = (n)-1; i >= 0; i--)
#define rep2(i, l, r) for (int i = (l); i < (r); i++)
#define per2(i, l, r) for (int i = (r)-1; i >= (l); i--)
#define each(e, v) for (auto &e : v)
#define MM << " " <<
#define pb push_back
#define eb emplace_back
#define all(x) begin(x), end(x)
#define rall(x) rbegin(x), rend(x)
#define sz(x) (int)x.size()
using ll = long long;
using pii = pair<int, int>;
using pil = pair<int, ll>;
using pli = pair<ll, int>;
using pll = pair<ll, ll>;

template <typename T>
using minheap = priority_queue<T, vector<T>, greater<T>>;

template <typename T>
using maxheap = priority_queue<T>;

template <typename T>
bool chmax(T &x, const T &y) {
    return (x < y) ? (x = y, true) : false;
}

template <typename T>
bool chmin(T &x, const T &y) {
    return (x > y) ? (x = y, true) : false;
}

template <typename T>
int flg(T x, int i) {
    return (x >> i) & 1;
}

int pct(int x) { return __builtin_popcount(x); }
int pct(ll x) { return __builtin_popcountll(x); }
int topbit(int x) { return (x == 0 ? -1 : 31 - __builtin_clz(x)); }
int topbit(ll x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
int botbit(int x) { return (x == 0 ? -1 : __builtin_ctz(x)); }
int botbit(ll x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }

template <typename T>
void print(const vector<T> &v, T x = 0) {
    int n = v.size();
    for (int i = 0; i < n; i++) cout << v[i] + x << (i == n - 1 ? '\n' : ' ');
    if (v.empty()) cout << '\n';
}

template <typename T>
void printn(const vector<T> &v, T x = 0) {
    int n = v.size();
    for (int i = 0; i < n; i++) cout << v[i] + x << '\n';
}

template <typename T>
int lb(const vector<T> &v, T x) {
    return lower_bound(begin(v), end(v), x) - begin(v);
}

template <typename T>
int ub(const vector<T> &v, T x) {
    return upper_bound(begin(v), end(v), x) - begin(v);
}

template <typename T>
void rearrange(vector<T> &v) {
    sort(begin(v), end(v));
    v.erase(unique(begin(v), end(v)), end(v));
}

template <typename T>
vector<int> id_sort(const vector<T> &v, bool greater = false) {
    int n = v.size();
    vector<int> ret(n);
    iota(begin(ret), end(ret), 0);
    sort(begin(ret), end(ret), [&](int i, int j) { return greater ? v[i] > v[j] : v[i] < v[j]; });
    return ret;
}

template <typename T>
void reorder(vector<T> &a, const vector<int> &ord) {
    int n = a.size();
    vector<T> b(n);
    for (int i = 0; i < n; i++) b[i] = a[ord[i]];
    swap(a, b);
}

template <typename T>
T floor(T x, T y) {
    assert(y != 0);
    if (y < 0) x = -x, y = -y;
    return (x >= 0 ? x / y : (x - y + 1) / y);
}

template <typename T>
T ceil(T x, T y) {
    assert(y != 0);
    if (y < 0) x = -x, y = -y;
    return (x >= 0 ? (x + y - 1) / y : x / y);
}

template <typename S, typename T>
pair<S, T> operator+(const pair<S, T> &p, const pair<S, T> &q) {
    return make_pair(p.first + q.first, p.second + q.second);
}

template <typename S, typename T>
pair<S, T> operator-(const pair<S, T> &p, const pair<S, T> &q) {
    return make_pair(p.first - q.first, p.second - q.second);
}

template <typename S, typename T>
istream &operator>>(istream &is, pair<S, T> &p) {
    S a;
    T b;
    is >> a >> b;
    p = make_pair(a, b);
    return is;
}

template <typename S, typename T>
ostream &operator<<(ostream &os, const pair<S, T> &p) {
    return os << p.first << ' ' << p.second;
}

struct io_setup {
    io_setup() {
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);
        cout << fixed << setprecision(15);
        cerr << fixed << setprecision(15);
    }
} io_setup;

constexpr int inf = (1 << 30) - 1;
constexpr ll INF = (1LL << 60) - 1;
// constexpr int MOD = 1000000007;
constexpr int MOD = 998244353;

template <typename T = string>
struct Suffix_Array {
    const T s;
    const int n;
    vector<int> SA, RANK;

    Suffix_Array(const T &s) : s(s), n(s.size()) {
        int n = s.size();
        int mi = *min_element(begin(s), end(s)), ma = *max_element(begin(s), end(s));
        vector<int> a(n);
        if (ma - mi >= n) {
            a = compress(s);
        } else {
            for (int i = 0; i < n; i++) a[i] = s[i] - mi;
        }
        SA = SAIS(a);
        RANK.resize(n);
        for (int i = 0; i < n; i++) RANK[SA[i]] = i;
    }

    vector<int> compress(const T &a) {
        int n = a.size();
        T v = a;
        sort(begin(v), end(v));
        v.erase(unique(begin(v), end(v)), end(v));
        vector<int> ret(n);
        for (int i = 0; i < n; i++) ret[i] = std::lower_bound(begin(v), end(v), a[i]) - begin(v);
        return ret;
    }

    vector<int> SAIS(const vector<int> &a) {
        int n = a.size();
        vector<int> ls_type(n); // 0:s 型、1:l 型
        ls_type[n - 1] = 1;
        for (int i = n - 2; i >= 0; i--) {
            ls_type[i] = ls_type[i + 1];
            if (a[i] < a[i + 1]) ls_type[i] = 0;
            if (a[i] > a[i + 1]) ls_type[i] = 1;
        }
        vector<int> lms, lms_id(n, -1);
        for (int i = 1; i < n; i++) {
            if (ls_type[i - 1] == 1 && ls_type[i] == 0) {
                lms_id[i] = lms.size();
                lms.push_back(i);
            }
        }
        int m = lms.size();
        int ma = *max_element(begin(a), end(a));
        vector<int> l(ma + 1, 0), r(ma + 1, 0);
        for (int i = 0; i < n; i++) r[a[i]]++;
        for (int i = 0; i < ma; i++) r[i + 1] += r[i];
        for (int i = 0; i < ma; i++) l[i + 1] = r[i];
        if (m == 0) {
            vector<int> sa(n);
            for (int i = n - 1; i >= 0 && ls_type[i] == 1; i--) {
                int e = a[i];
                sa[l[e]++] = i;
            }
            for (int i = 0; i < n && ls_type[i] == 0; i++) {
                int e = a[i];
                sa[l[e]++] = i;
            }
            return sa;
        }

        auto induced_sort = [&](vector<int> &sa) {
            auto ml = l, mr = r;
            sa[ml[a[n - 1]]++] = n - 1;
            for (int i = 0; i < n; i++) {
                int e = sa[i];
                if (e > 0 && ls_type[e - 1] == 1) sa[ml[a[e - 1]]++] = e - 1;
            }
            for (int i = n - 1; i >= 0; i--) {
                int e = sa[i];
                if (e > 0 && ls_type[e - 1] == 0) sa[--mr[a[e - 1]]] = e - 1;
            }
        };

        vector<int> sa(n, -1);
        for (int i = m - 1; i >= 0; i--) {
            int e = lms[i];
            sa[--r[a[e]]] = e;
        }
        for (auto &e : lms) r[a[e]]++;
        induced_sort(sa);
        vector<int> sa_lms;
        sa_lms.reserve(m);
        for (auto &e : sa) {
            if (lms_id[e] != -1) sa_lms.push_back(lms_id[e]);
        }

        // a[lms[i]:lms[i+1]] と a[lms[j]:lms[j+1]] の一致判定
        auto same = [&](int i, int j) {
            if (i == m - 1 || j == m - 1) return false;
            if (lms[i + 1] - lms[i] != lms[j + 1] - lms[j]) return false;
            int d = lms[i + 1] - lms[i];
            for (int k = 0; k <= d; k++) {
                if (a[lms[i] + k] != a[lms[j] + k]) return false;
            }
            return true;
        };

        vector<int> rank_lms(m);
        rank_lms[sa_lms[0]] = 0;
        for (int i = 1; i < m; i++) {
            rank_lms[sa_lms[i]] = rank_lms[sa_lms[i - 1]];
            if (!same(sa_lms[i - 1], sa_lms[i])) rank_lms[sa_lms[i]]++;
        }
        vector<int> b(m);
        for (int i = 0; i < m; i++) {
            int e = lms[i];
            b[i] = rank_lms[lms_id[e]];
        }
        sa_lms = SAIS(b);
        fill(begin(sa), end(sa), -1);
        for (auto &e : lms) r[a[e]]--;
        for (auto &e : sa_lms) sa[r[a[lms[e]]]++] = lms[e];
        induced_sort(sa);
        return sa;
    }

    int operator[](int i) const { return SA[i]; }

    int rank(int i) const { return RANK[i]; }

    int size() const { return n; }

    bool compare_substr(const T &t, int si = 0, int ti = 0) const {
        int m = t.size();
        while (si < n && ti < m) {
            if (s[si] != t[ti]) return s[si] < t[ti];
            si++, ti++;
        }
        return si == n && ti < m;
    }

    // 辞書順で t 以降となるもので最初の接尾辞
    int lower_bound(const T &t) const {
        int l = -1, r = n;
        while (r - l > 1) {
            int m = (l + r) / 2;
            (compare_substr(t, SA[m]) ? l : r) = m;
        }
        return r;
    }

    int upper_bound(T t) const {
        t.back()++;
        return lower_bound(t);
    }
};

template <typename T = string>
struct Longest_Common_Prefix_Array {
    vector<int> lcp;
    const Suffix_Array<T> sa;
    const int n;

    Longest_Common_Prefix_Array(const Suffix_Array<T> &sa) : sa(sa), n(sa.size()) {
        lcp.resize(n - 1);
        int h = 0;
        for (int i = 0; i < n; i++) {
            if (sa.rank(i) + 1 < n) {
                int j = sa[sa.rank(i) + 1];
                while (max(i, j) + h < n && sa.s[i + h] == sa.s[j + h]) h++;
                lcp[sa.rank(i)] = h;
                if (h > 0) h--;
            }
        }
    }

    int operator[](int i) const { return lcp[i]; }
};

template <typename Monoid>
struct Segment_Tree {
    using M = typename Monoid::V;
    int n, m;
    vector<M> seg;

    // f(f(a,b),c) = f(a,f(b,c)), f(e1,a) = f(a,e1) = a

    Segment_Tree(const vector<M> &v) : n(v.size()) {
        m = 1;
        while (m < n) m <<= 1;
        seg.assign(2 * m, Monoid::id);
        copy(begin(v), end(v), begin(seg) + m);
        build();
    }

    Segment_Tree(int n, M x = Monoid::id) : Segment_Tree(vector<M>(n, x)) {}

    void set(int i, const M &x) { seg[m + i] = x; }

    void build() {
        for (int i = m - 1; i > 0; i--) seg[i] = Monoid::merge(seg[2 * i], seg[2 * i + 1]);
    }

    void update(int i, const M &x, bool apply = false) {
        seg[i + m] = apply ? Monoid::merge(seg[i + m], x) : x;
        i += m;
        while (i >>= 1) seg[i] = Monoid::merge(seg[2 * i], seg[2 * i + 1]);
    }

    M query(int l, int r) const {
        l = max(l, 0), r = min(r, n);
        M L = Monoid::id, R = Monoid::id;
        l += m, r += m;
        while (l < r) {
            if (l & 1) L = Monoid::merge(L, seg[l++]);
            if (r & 1) R = Monoid::merge(seg[--r], R);
            l >>= 1, r >>= 1;
        }
        return Monoid::merge(L, R);
    }

    M operator[](int i) const { return seg[m + i]; }

    template <typename C>
    int find_subtree(int i, const C &check, M &x, int type) const {
        while (i < m) {
            M nxt = type ? Monoid::merge(seg[2 * i + type], x) : Monoid::merge(x, seg[2 * i + type]);
            if (check(nxt)) {
                i = 2 * i + type;
            } else {
                x = nxt;
                i = 2 * i + (type ^ 1);
            }
        }
        return i - m;
    }

    // check(区間 [l,r] での演算結果) を満たす最小の r (存在しなければ n)
    template <typename C>
    int find_first(int l, const C &check) const {
        M L = Monoid::id;
        int a = l + m, b = 2 * m;
        while (a < b) {
            if (a & 1) {
                M nxt = Monoid::merge(L, seg[a]);
                if (check(nxt)) return find_subtree(a, check, L, 0);
                L = nxt;
                a++;
            }
            a >>= 1, b >>= 1;
        }
        return n;
    }

    // check((区間 [l,r) での演算結果)) を満たす最大の l (存在しなければ -1)
    template <typename C>
    int find_last(int r, const C &check) const {
        M R = Monoid::id;
        int a = m, b = r + m;
        while (a < b) {
            if ((b & 1) || a == 1) {
                M nxt = Monoid::merge(seg[--b], R);
                if (check(nxt)) return find_subtree(b, check, R, 1);
                R = nxt;
            }
            a >>= 1, b >>= 1;
        }
        return -1;
    }
};

// sum
template <typename T>
struct Plus_Monoid {
    using V = T;
    static constexpr V merge(const V &a, const V &b) { return a + b; };
    static const V id;
};

template <typename T>
const T Plus_Monoid<T>::id = 0;

// prod
template <typename T>
struct Product_Monoid {
    using V = T;
    static constexpr V merge(const V &a, const V &b) { return a * b; };
    static const V id;
};

template <typename T>
const T Product_Monoid<T>::id = 1;

// min
template <typename T>
struct Min_Monoid {
    using V = T;
    static constexpr V merge(const V &a, const V &b) { return min(a, b); };
    static const V id;
};

template <typename T>
constexpr T Min_Monoid<T>::id = numeric_limits<T>::max() / 2;

// max
template <typename T>
struct Max_Monoid {
    using V = T;
    static constexpr V merge(V a, V b) { return max(a, b); };
    static const V id;
};

template <typename T>
constexpr T Max_Monoid<T>::id = -(numeric_limits<T>::max() / 2);

// 代入
template <typename T>
struct Update_Monoid {
    using V = T;
    static constexpr V merge(const V &a, const V &b) {
        if (a == id) return b;
        if (b == id) return a;
        return b;
    }
    static const V id;
};

template <typename T>
constexpr T Update_Monoid<T>::id = numeric_limits<T>::max();

// min count (T:最大値の型、S:個数の型)
template <typename T, typename S>
struct Min_Count_Monoid {
    using V = pair<T, S>;
    static constexpr V merge(const V &a, const V &b) {
        if (a.first < b.first) return a;
        if (a.first > b.first) return b;
        return V(a.first, a.second + b.second);
    }
    static const V id;
};

template <typename T, typename S>
constexpr pair<T, S> Min_Count_Monoid<T, S>::id = make_pair(numeric_limits<T>::max() / 2, 0);

// max count (T:最大値の型、S:個数の型)
template <typename T, typename S>
struct Max_Count_Monoid {
    using V = pair<T, S>;
    static constexpr V merge(const V &a, const V &b) {
        if (a.first > b.first) return a;
        if (a.first < b.first) return b;
        return V(a.first, a.second + b.second);
    }
    static const V id;
};

template <typename T, typename S>
constexpr pair<T, S> Max_Count_Monoid<T, S>::id = make_pair(-(numeric_limits<T>::max() / 2), 0);

// 一次関数 ax+b の合成 (左から順に作用)
template <typename T>
struct Affine_Monoid {
    using V = pair<T, T>;
    static constexpr V merge(const V &a, const V &b) { return V(a.first * b.first, a.second * b.first + b.second); };
    static const V id;
};

template <typename T>
const pair<T, T> Affine_Monoid<T>::id = make_pair(1, 0);

// モノイドの直積
template <typename Monoid_1, typename Monoid_2>
struct Cartesian_Product_Monoid {
    using V1 = typename Monoid_1::V;
    using V2 = typename Monoid_2::V;
    using V = pair<V1, V2>;
    static constexpr V merge(const V &a, const V &b) { return V(Monoid_1::merge(a.first, b.first), Monoid_2::merge(a.second, b.second)); }
    static const V id;
};

template <typename Monoid_1, typename Monoid_2>
const pair<typename Monoid_1::V, typename Monoid_2::V> Cartesian_Product_Monoid<Monoid_1, Monoid_2>::id = make_pair(Monoid_1::id, Monoid_2::id);

// 行列積 (l*r)
template <typename T, int n>
struct Matrix_Monoid {
    using V = array<array<T, n>, n>;
    static constexpr V I() {
        V ret;
        for (int i = 0; i < n; i++) fill(begin(ret[i]), end(ret[i]), T(0));
        for (int i = 0; i < n; i++) ret[i][i] = 1;
        return ret;
    }
    static constexpr V merge(V l, V r) {
        V ret;
        for (int i = 0; i < n; i++) fill(begin(ret[i]), end(ret[i]), T(0));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < n; k++) ret[i][k] += l[i][j] * r[j][k];
            }
        }
        return ret;
    }
    static const V id;
};

template <typename T, int n>
const array<array<T, n>, n> Matrix_Monoid<T, n>::id = Matrix_Monoid<T, n>::I();

// 行列積 (r*l)
template <typename T, int n>
struct Matrix_Monoid_Rev {
    using V = array<array<T, n>, n>;
    static constexpr V I() {
        V ret;
        for (int i = 0; i < n; i++) fill(begin(ret[i]), end(ret[i]), T(0));
        for (int i = 0; i < n; i++) ret[i][i] = 1;
        return ret;
    }
    static constexpr V merge(V l, V r) {
        V ret;
        for (int i = 0; i < n; i++) fill(begin(ret[i]), end(ret[i]), T(0));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < n; k++) ret[i][k] += r[i][j] * l[j][k];
            }
        }
        return ret;
    }
    static const V id;
};

template <typename T, int n>
const array<array<T, n>, n> Matrix_Monoid_Rev<T, n>::id = Matrix_Monoid_Rev<T, n>::I();

// range add range min
template <typename T>
struct Min_Plus_Acted_Monoid {
    using Monoid = Min_Monoid<T>;
    using Operator = Plus_Monoid<T>;
    using M = T;
    using O = T;
    static constexpr M merge(const M &a, const O &b) { return a + b; };
};

// range add range max
template <typename T>
struct Max_Plus_Acted_Monoid {
    using Monoid = Max_Monoid<T>;
    using Operator = Plus_Monoid<T>;
    using M = T;
    using O = T;
    static constexpr M merge(const M &a, const O &b) { return a + b; };
};

// range add range min count (T:最小値の型、S:個数の型)
template <typename T, typename S>
struct Min_Count_Add_Acted_Monoid {
    using Monoid = Min_Count_Monoid<T, S>;
    using Operator = Plus_Monoid<T>;
    using M = pair<T, S>;
    using O = T;
    static constexpr M merge(const M &a, const O &b) { return make_pair(a.first + b, a.second); };
};

// range add range max count (T:最大値の型、S:個数の型)
template <typename T, typename S>
struct Max_Count_Add_Acted_Monoid {
    using Monoid = Max_Count_Monoid<T, S>;
    using Operator = Plus_Monoid<T>;
    using M = pair<T, S>;
    using O = T;
    static constexpr M merge(const M &a, const O &b) { return make_pair(a.first + b, a.second); };
};

// range add range sum
template <typename T>
struct Plus_Plus_Acted_Monoid {
    using Monoid = Cartesian_Product_Monoid<Plus_Monoid<T>, Plus_Monoid<int>>;
    using Operator = Plus_Monoid<T>;
    using M = pair<T, int>;
    using O = T;
    static constexpr M merge(const M &a, const O &b) { return M(a.first + b * a.second, a.second); }
};

// range update range sum
template <typename T>
struct Plus_Update_Acted_Monoid {
    using Monoid = Cartesian_Product_Monoid<Plus_Monoid<T>, Plus_Monoid<int>>;
    using Operator = Update_Monoid<T>;
    using M = pair<T, int>;
    using O = T;
    static constexpr M merge(const M &a, const O &b) { return b == Operator::id ? a : M(b * a.second, a.second); }
};

// range update range min
template <typename T>
struct Min_Update_Acted_Monoid {
    using Monoid = Min_Monoid<T>;
    using Operator = Update_Monoid<T>;
    using M = T;
    using O = T;
    static constexpr M merge(const M &a, const O &b) { return b == Operator::id ? a : b; }
};

// range update range max
template <typename T>
struct Max_Update_Acted_Monoid {
    using Monoid = Max_Monoid<T>;
    using Operator = Update_Monoid<T>;
    using M = T;
    using O = T;
    static constexpr M merge(const M &a, const O &b) { return b == Operator::id ? a : b; }
};

// range affine range sum
template <typename T>
struct Plus_Affine_Acted_Monoid {
    using Monoid = Cartesian_Product_Monoid<Plus_Monoid<T>, Plus_Monoid<T>>;
    using Operator = Affine_Monoid<T>;
    using M = pair<T, T>;
    using O = pair<T, T>;
    static constexpr M merge(const M &a, const O &b) { return M(b.first * a.first + b.second * a.second, a.second); };
};

void solve() {
    int N;
    string S;
    cin >> N >> S;

    Suffix_Array sa(S);
    Longest_Common_Prefix_Array lcp(sa);

    vector<int> v(N - 1);
    rep(i, N - 1) v[i] = lcp[i];
    Segment_Tree<Min_Monoid<int>> seg(v);

    int ans = 0;

    rep2(i, 1, N) {
        int a = sa.rank(0), b = sa.rank(i);
        if (a < b) {
            ans++;
            continue;
        }
        int x = seg.query(b, a);
        if (i < N - i && i <= x) ans++;
    }

    cout << ans << '\n';
}

int main() {
    int T = 1;
    cin >> T;
    while (T--) solve();
}
0