結果
| 問題 |
No.2606 Mirror Relay
|
| コンテスト | |
| ユーザー |
hitonanode
|
| 提出日時 | 2024-05-03 17:32:42 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 53 ms / 2,000 ms |
| コード長 | 4,134 bytes |
| コンパイル時間 | 1,568 ms |
| コンパイル使用メモリ | 127,036 KB |
| 実行使用メモリ | 37,772 KB |
| 最終ジャッジ日時 | 2024-11-24 20:35:21 |
| 合計ジャッジ時間 | 4,527 ms |
|
ジャッジサーバーID (参考情報) |
judge2 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 69 |
ソースコード
#line 1 "string/test/palindromic_tree.yuki2606.test.cpp"
#define PROBLEM "https://yukicoder.me/problems/no/2606"
#line 2 "string/palindromic_tree.hpp"
#include <map>
#include <string>
#include <vector>
// Palindromic tree / Eertree (回文木)
namespace palindromic_tree {
template <class Key> class Node {
int suffix_link_ = -1; // このノードからのsuffix link (suffix の最長回文)
int length_ = -1; // このノードが表す回文の長さ
std::map<Key, int> children;
public:
Node() = default;
Node(int suffix_link, int length) : suffix_link_(suffix_link), length_(length) {}
int suffix_link() const { return suffix_link_; }
int length() const { return length_; }
int get_child(Key c) const {
auto it = children.find(c);
return (it == children.end()) ? -1 : it->second;
}
void set_child(int c, int nxt_idx) { children[c] = nxt_idx; }
template <class OStream> friend OStream &operator<<(OStream &os, const Node &node) {
os << "Node(suffix_link=" << node.suffix_link() << ", length=" << node.length()
<< ", children={";
for (const auto &[c, nxt] : node.children) os << c << "->" << nxt << ", ";
return os << "})";
}
};
template <class Key> struct Tree {
std::vector<Node<Key>> nodes;
Tree() { nodes = {Node<Key>(0, -1), Node<Key>(0, 0)}; }
// nodes[cursor] は s[0:i] の suffix
// s[0:(i + 1)] の suffix で、 nodes[cursor] 自身とその先祖の最長回文を探す
int find_next_suffix(const std::vector<Key> &s, int i, int cursor) {
while (true) {
const int cur_len = nodes.at(cursor).length();
const int opposite_pos = i - cur_len - 1;
if (opposite_pos >= 0 and s.at(opposite_pos) == s.at(i)) return cursor;
cursor = nodes.at(cursor).suffix_link();
}
}
template <class Callback> void add_string(const std::vector<Key> &s, Callback callback) {
int cursor = 1;
for (int i = 0; i < (int)s.size(); ++i) {
cursor = find_next_suffix(s, i, cursor);
int ch = nodes.at(cursor).get_child(s.at(i));
if (ch < 0) {
const int nxt_cursor = nodes.size();
const int new_length = nodes.at(cursor).length() + 2;
int new_suffix_link_par = find_next_suffix(s, i, nodes.at(cursor).suffix_link());
int new_suffix_link = nodes.at(new_suffix_link_par).get_child(s.at(i));
if (new_suffix_link < 1) new_suffix_link = 1;
nodes.at(cursor).set_child(s.at(i), nxt_cursor);
nodes.push_back(Node<Key>(new_suffix_link, new_length));
cursor = nxt_cursor;
} else {
cursor = ch;
}
callback(i, cursor);
}
}
template <class Callback> void add_string(const std::string &s, Callback callback) {
add_string(std::vector<Key>{s.cbegin(), s.cend()}, callback);
}
template <class Vec> void add_string(const Vec &s) {
add_string(s, [](int, int) {});
}
};
} // namespace palindromic_tree
#line 3 "string/test/palindromic_tree.yuki2606.test.cpp"
#include <algorithm>
#include <iostream>
#line 8 "string/test/palindromic_tree.yuki2606.test.cpp"
using namespace std;
int main() {
cin.tie(nullptr), ios::sync_with_stdio(false);
string S;
cin >> S;
palindromic_tree::Tree<char> tree;
vector<long long> visitcnt(S.size() + 2);
tree.add_string(S, [&](int, int node_idx) { visitcnt.at(node_idx)++; });
const int V = tree.nodes.size();
for (int i = V - 1; i > 0; --i) visitcnt.at(tree.nodes.at(i).suffix_link()) += visitcnt.at(i);
vector<vector<int>> children(V);
for (int i = 1; i < V; ++i) children.at(tree.nodes.at(i).suffix_link()).push_back(i);
vector<long long> dp(V, 0);
for (int i = 0; i < V; ++i) {
dp.at(i) += visitcnt.at(i) * max(tree.nodes.at(i).length(), 0);
for (int ch : children.at(i)) dp.at(ch) += dp.at(i);
}
cout << *max_element(dp.begin(), dp.end()) << '\n';
}
hitonanode