zoukankan      html  css  js  c++  java
  • [CF427D] Match & Catch

    Description

    求在两个给定字符串中各只出现一次的最短的公共子串。

    Solution

    对两个给定串建立广义 SAM,对每个结点,分别记录源于各个串的 (endpos) 集合的大小 (cnt[i][0], cnt[i][1])

    遍历所有节点 (p),若 (cnt[p][0] = 1 and cnt[p][1] = 1) 则该点合法,用它的 (minlen) 更新答案

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N = 2000005;
    struct SAM
    {
        int len[N], ch[N][26], fa[N], ind, last, cnt[N][2], a[N], t[N];
        SAM()
        {
            ind = last = 1;
        }
        inline int extend(int id)
        {
            if(ch[last][id] && len[last]+1==len[ch[last][id]]) return ch[last][id]; //!
            int cur = (++ ind), p, tmp, flag = 0; //!
            len[cur] = len[last] + 1;
            for (p = last; p && !ch[p][id]; p = fa[p]) ch[p][id] = cur;
            if (!p) fa[cur] = 1;
            else
            {
                int q = ch[p][id];
                if (len[q] == len[p] + 1) fa[cur] = q;
                else
                {
                    if(p==last) flag=1; //!
                    tmp = (++ ind);
                    len[tmp] = len[p] + 1;
                    for(int i=0; i<26; i++) ch[tmp][i] = ch[q][i];
                    fa[tmp] = fa[q];
                    for (; p && ch[p][id] == q; p = fa[p]) ch[p][id] = tmp;
                    fa[cur] = fa[q] = tmp;
                }
            }
            last = cur;
            return flag ? tmp : cur;//!
        }
        void extend(string s, int id)
        {
            for(int i=0; i<s.length(); i++)
            {
                last = extend(s[i]-'a');
                cnt[last][id]=1;
            }
            last = 1;
        }
        void calc()
        {
            memset(t, 0, sizeof t);
            for(int i=1; i<=ind; i++) t[len[i]]++;
            for(int i=1; i<=ind; i++) t[i]+=t[i-1];
            for(int i=1; i<=ind; i++) a[t[len[i]]--]=i;
            for(int id=0; id<2; id++) for(int i=ind; i>=1; --i) cnt[fa[a[i]]][id]+=cnt[a[i]][id];
            cnt[1][0] = cnt[1][1] = 0;
        }
        int solve()
        {
            int ans=1e9;
            for(int i=1;i<=ind;i++) if(cnt[i][0]==1 && cnt[i][1]==1) ans=min(ans,len[fa[i]]+1);
            return ans > 1e8 ? -1 : ans;
        }
    } sam;
    
    signed main()
    {
        ios::sync_with_stdio(false);
        int n;
        string str;
        for(int i=1; i<=2; i++)
        {
            cin>>str;
            sam.extend(str,i-1);
        }
        sam.calc();
        cout<<sam.solve()<<endl;
    }
    
    
    
    
    
  • 相关阅读:
    「NOI2017」蔬菜 解题报告
    线性代数
    idea创建maven的web工程
    logback和slf4j的使用之logger使用
    英雄之言 罗隐
    论英雄
    英雄--偶得佳文不知出处
    日志
    延迟加载线程安全的单例--最佳方式,通过内部类
    linux下安装jdk8
  • 原文地址:https://www.cnblogs.com/mollnn/p/13581246.html
Copyright © 2011-2022 走看看