Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // An AC a day keeps the doctor away. #pragma GCC optimize("Ofast")
- #include <bits/stdc++.h>
- #ifdef local
- #define safe std::cerr<<__PRETTY_FUNCTION__<<" line "<<__LINE__<<" safe\n"
- #define debug(args...) qqbx(#args, args)
- #define orange(args...) danb(#args, args)
- #define INFO(msg) qqbx(msg, "")
- using std::cerr;
- template <typename ...T> void qqbx(const char *s, T ...args) {
- int cnt = sizeof...(T);
- ((cerr << "\e[1;32m(" << s << ") = ("), ..., (cerr << args << (--cnt ? ", " : ")\e[0m\n")));
- }
- template <typename T> void danb(const char *s, T L, T R) {
- cerr << "\e[1;32m[ " << s << " ] = [ ";
- for (int f = 0; L != R; ++L) cerr << (f++ ? ", " : "") << *L;
- cerr << " ]\e[0m\n";
- }
- #else
- #define safe ((void)0)
- #define debug(...) ((void)0)
- #define orange(...) ((void)0)
- #define INFO(...) ((void)0)
- #endif // local
- #define all(v) begin(v),end(v)
- using namespace std;
- const int maxn = 200025;
- const int inf = 1e9;
- struct RMQ {
- vector<int> st[20];
- template <typename T>
- void build(T L, T R) {
- st[0].assign(L, R);
- int n = st[0].size();
- for (int L = 1; L < 20; L++) {
- st[L].resize(n);
- int len = 1 << (L - 1);
- for (int i = 0; i + len * 2 <= n; i++) {
- st[L][i] = min(st[L-1][i], st[L-1][i + len]);
- }
- }
- }
- int query(int l, int r) {
- if (l == r) return inf;
- // [l, r)
- int lev = __lg(r - l), len = 1 << lev;
- return min(st[lev][l], st[lev][r - len]);
- }
- };
- struct SuffixArray {
- vector<int> sa, rk, hei;
- RMQ rmq;
- SuffixArray(const string &s) : sa(s.size()), rk(s.size()), hei(s.size()) {
- int n = s.size();
- for (int i = 0; i < n; i++) {
- sa[i] = i;
- rk[i] = s[i];
- }
- for (int L = 1; L < n; L <<= 1) {
- auto cmp = [&](int a, int b) {
- if (rk[a] != rk[b])
- return rk[a] < rk[b];
- int ra = a+L < n ? rk[a+L] : -1;
- int rb = b+L < n ? rk[b+L] : -1;
- return ra < rb;
- };
- sort(sa.begin(), sa.end(), cmp);
- vector<int> nrk(n);
- nrk[sa[0]] = 0;
- for (int i = 1; i < n; i++)
- nrk[sa[i]] = nrk[sa[i-1]] + cmp(sa[i-1], sa[i]);
- rk = nrk;
- }
- for (int i = 0, h = 0; i < n; i++) {
- if (!rk[i]) {
- h = 0;
- continue;
- }
- int j = sa[rk[i]-1];
- while (i+h < n && j+h < n && s[i+h] == s[j+h]) ++h;
- hei[rk[i]] = h;
- if (h > 0) --h;
- }
- debug(s);
- orange(all(sa));
- orange(all(hei));
- orange(all(rk));
- rmq.build(hei.begin(), hei.end());
- }
- int query(int l, int r) {
- assert (l < r);
- return rmq.query(l+1, r+1);
- }
- };
- int pa[maxn], sz[maxn];
- int anc(int x) {
- return x==pa[x] ? x : pa[x]=anc(pa[x]);
- }
- set<int> stA[maxn], stB[maxn];
- signed main() {
- ios_base::sync_with_stdio(0), cin.tie(0);
- string A, B;
- cin >> A >> B;
- auto reversed = [](string s) {
- reverse(all(s));
- return s;
- };
- string T = "$$" + A + "##" + B + "&&";
- SuffixArray SA(T);
- SuffixArray rSA(reversed(T));
- vector<int> ord(T.size() - 1);
- iota(all(ord), 1);
- sort(all(ord), [&rSA](int x, int y) { return rSA.hei[x] > rSA.hei[y]; });
- for (int i = -1; i+1 < (int)A.size(); i++) {
- int j = i + 2;
- stA[rSA.rk[T.size() - 1 - j]].insert(SA.rk[j+2]);
- }
- for (int i = -1; i+1 < (int)B.size(); i++) {
- int j = i + A.size() + 4;
- stB[rSA.rk[T.size() - 1 - j]].insert(SA.rk[j+2]);
- }
- auto getMaxLCP = [&SA, &rSA, &T](set<int> &st, int x) {
- pair<int,int> res(-inf, -inf);
- auto it = st.lower_bound(x);
- if (it != st.begin())
- res = max(res, make_pair(SA.query(*prev(it), x), *prev(it)));
- if (it != st.end())
- res = max(res, make_pair(SA.query(x, *it), *it));
- return res;
- };
- tuple<int,int,int> ans(-inf, -inf, -inf);
- auto join = [&getMaxLCP, &SA, &ans](int x, int y, int h) {
- x = anc(x);
- y = anc(y);
- assert (x != y);
- if (sz[x] < sz[y]) swap(x, y);
- for (int p: stA[y]) {
- auto [l, q] = getMaxLCP(stB[x], p);
- if (q != -inf)
- ans = max(ans, make_tuple(h + l + 1, SA.sa[p] - h - 1, SA.sa[q] - h - 1));
- }
- for (int p: stB[y]) {
- auto [l, q] = getMaxLCP(stA[x], p);
- if (q != -inf)
- ans = max(ans, make_tuple(h + l + 1, SA.sa[q] - h - 1, SA.sa[p] - h - 1));
- }
- for (int p: stA[y]) stA[x].insert(p);
- for (int p: stB[y]) stB[x].insert(p);
- stA[y].clear();
- stB[y].clear();
- pa[y] = x;
- sz[x] += sz[y];
- };
- for (int i = 0; i < maxn; i++) pa[i] = i, sz[i] = 1;
- for (int x: ord) {
- int h = rSA.hei[x];
- join(x-1, x, h);
- }
- auto [len, p, q] = ans;
- cout << T.substr(p, len) << '\n' << T.substr(q, len) << '\n';
- }
Advertisement
Add Comment
Please, Sign In to add comment