結果
問題 | No.273 回文分解 |
ユーザー |
![]() |
提出日時 | 2022-03-16 03:06:12 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 4 ms / 2,000 ms |
コード長 | 6,487 bytes |
コンパイル時間 | 3,043 ms |
コンパイル使用メモリ | 210,720 KB |
最終ジャッジ日時 | 2025-01-28 09:50:12 |
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 32 |
ソースコード
#include<bits/stdc++.h>using namespace std;using int64 = long long;//const int mod = 1e9 + 7;const int mod = 998244353;const int64 infll = (1LL << 62) - 1;const int inf = (1 << 30) - 1;struct IoSetup {IoSetup() {cin.tie(nullptr);ios::sync_with_stdio(false);cout << fixed << setprecision(10);cerr << fixed << setprecision(10);}} iosetup;template< typename T1, typename T2 >ostream &operator<<(ostream &os, const pair< T1, T2 > &p) {os << p.first << " " << p.second;return os;}template< typename T1, typename T2 >istream &operator>>(istream &is, pair< T1, T2 > &p) {is >> p.first >> p.second;return is;}template< typename T >ostream &operator<<(ostream &os, const vector< T > &v) {for(int i = 0; i < (int) v.size(); i++) {os << v[i] << (i + 1 != v.size() ? " " : "");}return os;}template< typename T >istream &operator>>(istream &is, vector< T > &v) {for(T &in: v) is >> in;return is;}template< typename T1, typename T2 >inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }template< typename T1, typename T2 >inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }template< typename T = int64 >vector< T > make_v(size_t a) {return vector< T >(a);}template< typename T, typename... Ts >auto make_v(size_t a, Ts... ts) {return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...));}template< typename T, typename V >typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) {t = v;}template< typename T, typename V >typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) {for(auto &e: t) fill_v(e, v);}template< typename F >struct FixPoint : F {FixPoint(F &&f) : F(forward< F >(f)) {}template< typename... Args >decltype(auto) operator()(Args &&... args) const {return F::operator()(*this, forward< Args >(args)...);}};template< typename F >inline decltype(auto) MFP(F &&f) {return FixPoint< F >{forward< F >(f)};}/*** @brief Palindromic Tree(回文木)* @see https://math314.hateblo.jp/entry/2016/12/19/005919* @docs docs/palindromic-tree.md*/template< typename T = char >struct PalindromicTree {public:struct Node {map< T, int > link; // 子のidxint suffix_link; // 最長回文接尾辞のidxint len; // 対応する回文の長さvector< int > idx; // 対応する回文を最長回文接尾辞とするidxint delta_link; // 差分が異なる最長回文接尾辞のidxNode() = default;Node(int suf, int len) : suffix_link(suf), len(len), delta_link(-1) {}};vector< Node > ns;int ptr;vector< T > vs;private:int find_prev_palindrome(int cur) const {int pos = (int) vs.size() - 1;for(;;) {int rev = pos - 1 - ns[cur].len;if(rev >= 0 and vs[rev] == vs.back()) break;cur = ns[cur].suffix_link;}return cur;}bool output_dfs(int v, int id, vector< T > &ret) const {if(v == id) return true;for(auto &nxt: ns[v].link) {if(output_dfs(nxt.second, id, ret)) {ret.emplace_back(nxt.first);return true;}}return false;}public:PalindromicTree() : ptr(0) {ns.emplace_back(0, -1); // 長さ -1ns.emplace_back(0, 0); // 長さ 0}PalindromicTree(const string &S) : PalindromicTree() {add(S);}int diff(int t) const {if(ns[t].suffix_link <= 0) return -1;return ns[t].len - ns[ns[t].suffix_link].len;}int add(const T &x) {int idx = (int) vs.size();vs.emplace_back(x);int cur = find_prev_palindrome(ptr);auto res = ns[cur].link.insert(make_pair(x, (int) ns.size()));ptr = res.first->second;if(res.second) {ns.emplace_back(-1, ns[cur].len + 2);if(ns.back().len == 1) {ns.back().suffix_link = 1;} else {ns.back().suffix_link = ns[find_prev_palindrome(ns[cur].suffix_link)].link[x];}if(diff(ptr) == diff(ns.back().suffix_link)) {ns.back().delta_link = ns[ns.back().suffix_link].delta_link;} else {ns.back().delta_link = ns.back().suffix_link;}}ns[ptr].idx.emplace_back(idx);return ptr;}// add(x) のあとに呼び出す// * init(node_idx, pos): 頂点 node_idx を S[pos,i] が回文のときの初期値にする// * apply(node_idx, pre_idx): 頂点 node_idx に 頂点 pre_idx の結果を加える// * update: S[i]を末尾とする回文の頂点番号の集合template< typename I, typename U >vector< int > update_dp(const I &init, const U &apply) {int i = (int) vs.size() - 1;int id = ptr;vector< int > update;while(ns[id].len > 0) {init(id, i + 1 - ns[ns[id].delta_link].len - diff(id));if(ns[id].suffix_link != ns[id].delta_link) {apply(id, ns[id].suffix_link);}update.emplace_back(id);id = ns[id].delta_link;}return update;}void add(const string &s) {for(auto &x: s) add(x);}vector< int > build_frequency() const {vector< int > ret(ns.size());for(int i = (int) ns.size() - 1; i > 0; i--) {ret[i] += (int) ns[i].idx.size();ret[ns[i].suffix_link] += ret[i];}return ret;}vector< T > output(int idx) const {if(idx == 0) return {-1};if(idx == 1) return {0};vector< T > ret;output_dfs(0, idx, ret);output_dfs(1, idx, ret);int start = (int) ret.size() - 1;if(ns[idx].len & 1) --start;for(int i = start; i >= 0; i--) {ret.emplace_back(ret[i]);}return ret;}int size() const {return (int) ns.size();}Node &operator[](int idx) {return ns[idx];}};int main() {string S;cin >> S;int N = (int) S.size();vector< int > dp1(N + 3, -inf), dp2(N + 1, -inf);PalindromicTree t;dp2[0] = 1;for(int i = 0; i < N; i++) {int id = t.add(S[i]);auto ret = t.update_dp([&](int id, int pos) {if(i + 1 - pos == N) dp1[id] = dp2[pos];else dp1[id] = max(dp2[pos], i + 1 - pos);},[&](int id, int par) {if(t[id].len == N) chmax(dp1[id], dp1[par]);else chmax(dp1[id], max(dp1[par], t[id].len));});for(auto &p: ret) chmax(dp2[i + 1], dp1[p]);}cout << dp2[N] << "\n";}