Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <memory>
- #include <vector>
- #include <string>
- #include <set>
- using namespace std;
- struct TStringSlice {
- const string& SourceString;
- size_t Start;
- shared_ptr<size_t> End;
- TStringSlice(const string& str, const size_t& start, shared_ptr<size_t> end)
- : SourceString(str), Start(start), End(end) {}
- TStringSlice(const string& str, const size_t& start, size_t end)
- : SourceString(str), Start(start), End(make_shared<size_t>(end)) {}
- char operator[](const size_t& i) const {
- return SourceString[Start + i];
- }
- void Update(const TStringSlice& other) {
- Start = other.Start;
- End = other.End;
- }
- size_t Length() const {
- return *End - this->Start;
- }
- string ToString() const {
- return SourceString.substr(Start, (*End) - Start);
- }
- TStringSlice Slice(int a, int b) const {
- size_t newStart = a == -1 ? Start : Start + a;
- if (b == -1)
- return TStringSlice(SourceString, newStart, End);
- return TStringSlice(SourceString, newStart, Start + b);
- }
- };
- struct TNode;
- struct TEdge {
- TStringSlice Value;
- TNode* Node;
- void Split(size_t index);
- };
- struct TNode {
- vector<TEdge> Children;
- TNode* Parent = nullptr;
- TNode* SuffixLink = nullptr;
- size_t ParentEdge = 0;
- int TextFlag = 0;
- TNode* Add(const TEdge& edge) {
- Children.push_back(edge);
- TEdge* createdEdge = &(Children[Children.size() - 1]);
- createdEdge->Node->Parent = this;
- createdEdge->Node->ParentEdge = Children.size() - 1;
- return edge.Node;
- }
- };
- void TEdge::Split(size_t index) {
- TNode* newNode = new TNode();
- newNode->Parent = Node->Parent;
- newNode->ParentEdge = Node->ParentEdge;
- Node->Parent = newNode;
- newNode->Add({Value.Slice(index, -1), Node});
- Node = newNode;
- Value.Update(Value.Slice(-1, index));
- }
- struct TCursor {
- TNode* Node;
- TEdge* Edge = nullptr;
- size_t Index = 0;
- void MoveToNode(TNode* node) {
- this->Node = node;
- Edge = nullptr;
- Index = 0;
- }
- void ChooseEdgeByChar(char chr) {
- for(TEdge& nodeEdge: Node->Children) {
- if (nodeEdge.Value[0] == chr) {
- Edge = &nodeEdge;
- Index = 0;
- break;
- }
- }
- }
- void MoveToParentEdge() {
- Edge = &(Node->Parent->Children[Node->ParentEdge]);
- Node = Node->Parent;
- Index = Edge->Value.Length() - 1;
- }
- bool Next(char chr) {
- if (!IsNode() && (Index + 1 >= Edge->Value.Length()))
- MoveToNode(Edge->Node);
- if (Edge == nullptr) {
- ChooseEdgeByChar(chr);
- return Edge != nullptr;
- }
- if (Edge->Value[Index + 1] != chr)
- return false;
- Index++;
- return true;
- }
- bool Prev() {
- if (IsNode()) {
- if (Node->Parent != nullptr) {
- MoveToParentEdge();
- return true;
- }
- return false;
- }
- if (Index == 0) {
- Edge = nullptr;
- return true;
- }
- Index--;
- return true;
- }
- bool IsNode() const {
- return Edge == nullptr;
- }
- };
- struct TCompactTrie {
- TNode Root;
- TCursor GetCursor() {
- return {&Root};
- }
- };
- struct TState {
- const string& SourceString;
- TCursor Cursor;
- int TextFlag;
- shared_ptr<size_t> End;
- TNode* LastMiddleNode;
- bool NeedUpdate;
- };
- void InsertString(const TStringSlice& str, TState& state);
- void Iterate(const TStringSlice& str, bool fastMode, TState& state);
- void GoBack(TState& state);
- void UpdateSuffixLinks(TState& state) {
- if (state.LastMiddleNode != nullptr) {
- state.LastMiddleNode->SuffixLink = state.Cursor.Node;
- }
- state.LastMiddleNode = state.Cursor.Node;
- }
- void UpdateTextFlag(TState& state) {
- set<TNode*> seenNodes;
- while (!state.Cursor.IsNode()) {
- state.Cursor.MoveToNode(state.Cursor.Edge->Node);
- if(seenNodes.find(state.Cursor.Node) == seenNodes.end()) {
- state.Cursor.Node->TextFlag |= state.TextFlag;
- seenNodes.insert(state.Cursor.Node);
- GoBack(state);
- }
- }
- }
- void InsertString(const TStringSlice& str, TState& state) {
- if (state.Cursor.IsNode()) {
- TNode* newNode = state.Cursor.Node->Add({str, new TNode()});
- newNode->TextFlag |= state.TextFlag;
- state.NeedUpdate = state.Cursor.Node->Parent != nullptr;
- state.Cursor.MoveToNode(newNode);
- } else {
- state.Cursor.Edge->Split(state.Cursor.Index + 1);
- state.Cursor.MoveToNode(state.Cursor.Edge->Node);
- UpdateSuffixLinks(state);
- TNode* newNode = state.Cursor.Node->Add({str, new TNode()});
- newNode->TextFlag |= state.TextFlag;
- state.Cursor.MoveToNode(newNode);
- state.NeedUpdate = true;
- }
- }
- void Iterate(const TStringSlice& str, bool fastMode, TState& state) {
- size_t index = 0;
- while (index < str.Length()) {
- if (!state.Cursor.Next(str[index])) {
- InsertString(str.Slice(index, -1), state);
- break;
- }
- if (fastMode) {
- size_t minLength = min(
- state.Cursor.Edge->Value.Length(),
- str.Length() - index
- ) - 1;
- state.Cursor.Index = minLength;
- index += minLength;
- }
- index++;
- }
- }
- TEdge* JumpToParent(TCursor& cursor) {
- cursor.Prev();
- TEdge* parentEdge = cursor.Edge;
- cursor.MoveToNode(cursor.Node);
- return parentEdge;
- }
- void GoBack(TState& state) {
- TEdge* edge = JumpToParent(state.Cursor);
- if (state.Cursor.Node->Parent != nullptr) {
- if (state.Cursor.Node->SuffixLink != nullptr) {
- state.Cursor.MoveToNode(state.Cursor.Node->SuffixLink);
- } else {
- GoBack(state);
- }
- Iterate(edge->Value, !edge->Node->Children.empty(), state);
- } else {
- Iterate(edge->Value.Slice(1, -1), !edge->Node->Children.empty(), state);
- }
- }
- void StartStep(TState& state) {
- state.NeedUpdate = true;
- while(state.NeedUpdate) {
- state.NeedUpdate = false;
- if (state.Cursor.IsNode()) {
- GoBack(state);
- } else {
- Iterate({state.SourceString, (*state.End) - 1, state.End}, false, state);
- }
- }
- }
- TCompactTrie* BuildSuffixTrie(const string& str, TCompactTrie* trie = nullptr, int textFlag = 0) {
- TCompactTrie* t = (trie == nullptr) ? new TCompactTrie() : trie;
- TState state { str, t->GetCursor(), textFlag, make_shared<size_t>(0), nullptr, false };
- (*state.End)++;
- Iterate({str, 0, state.End}, false, state);
- while((*state.End) < str.size()) {
- (*state.End)++;
- StartStep(state);
- state.LastMiddleNode = nullptr;
- }
- UpdateTextFlag(state);
- return t;
- }
- void ExtendTextFlags(TNode* node) {
- for (const TEdge& child: node->Children) {
- ExtendTextFlags(child.Node);
- node->TextFlag |= child.Node->TextFlag;
- }
- }
- TCompactTrie* BuildCommonSuffixTree(string& s1, string& s2) {
- TCompactTrie* trie = BuildSuffixTrie(s1, nullptr, 1);
- BuildSuffixTrie(s2, trie, 2);
- ExtendTextFlags(&(trie->Root));
- return trie;
- }
- size_t CalculateMaxCommonSubstringSize(const TNode& node) {
- if(node.Children.empty()) return -1;
- size_t maximalSize = 0;
- for(const TEdge& child : node.Children) {
- if(child.Node->TextFlag == 3) {
- maximalSize = max(
- maximalSize,
- child.Value.Length() + CalculateMaxCommonSubstringSize(*(child.Node))
- );
- }
- }
- return maximalSize;
- }
- void RestoreString(const TNode* node, string& outString) {
- while(node->Parent != nullptr) {
- const TEdge& x = node->Parent->Children[node->ParentEdge];
- outString.insert(0, x.Value.ToString());
- node = node->Parent;
- };
- }
- void FindCommonSubstringsBySpecifiedSize(
- const TNode& node,
- const size_t& maximalSize,
- const size_t& currentSize,
- set<string> & substrings
- ) {
- if(currentSize == maximalSize) {
- string foundSubstring;
- RestoreString(&node, foundSubstring);
- if (foundSubstring.back() == '$')
- foundSubstring.pop_back();
- substrings.insert(foundSubstring);
- return;
- }
- if(currentSize > maximalSize) {
- return;
- }
- for(const TEdge& child : node.Children) {
- if(child.Node->TextFlag == 3) {
- size_t nextLength = child.Value.Length();
- if(child.Node->Children.empty())
- nextLength--;
- FindCommonSubstringsBySpecifiedSize(
- *(child.Node),
- maximalSize,
- currentSize + nextLength,
- substrings
- );
- }
- }
- }
- void FindCommonSubstrings(TCompactTrie& trie, set<string> & results) {
- size_t maxLength = CalculateMaxCommonSubstringSize(trie.Root);
- FindCommonSubstringsBySpecifiedSize(
- trie.Root,
- maxLength,
- 0,
- results
- );
- }
- const char SENTINEL = '$';
- int main() {
- ios_base::sync_with_stdio(false);
- cin.tie(nullptr);
- string a, b;
- set<string> results;
- getline(cin, a);
- getline(cin, b);
- a += SENTINEL;
- b += SENTINEL;
- TCompactTrie* trie = BuildCommonSuffixTree(a, b);
- FindCommonSubstrings(*trie, results);
- bool sizePrinted = false;
- for(const string& result: results) {
- if(result.size() == 0) {
- break;
- }
- if(!sizePrinted) {
- cout << result.size();
- sizePrinted = true;
- }
- cout << "\n" << result;
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement