zoukankan      html  css  js  c++  java
  • [BZOJ 3145][Feyat cup 1.5]Str 解题报告

    [Feyat cup 1.5]Str

    Description
    Arcueid,白姬,真祖的公主。在和推倒贵看电影时突然对一个问题产生了兴趣:
    我们都知道真祖和死徒是有类似的地方。那么从现代科学的角度如何解释
    呢?自然就得研究遗传密码了。Arcueid得知了两者的DNA片段,想寻求一个
    DNA片段,使得其在两者的DNA中都出现过。
    我们知道公主的脑袋有点不太灵活,如果两个DNA片段只有一个位置不
    同,她也会将其认为是相同的。所以请您找出这样的最长的DNA片段吧。
    Input
    两行,每行一个字符串。
    Output
    一个整数,表示最长的 DNA 片段的长度。
    Sample Input
    aabbe
    acbbc
    Sample Output
    4
    HINT
    100% 的数据 n<=10^5;m<=10^5 。

    Sol:

    2015年集训队论文里有讲到这个题目

    Sam + Sa

    将a,b拼接起来,中间加一个特殊字符

    考虑后缀自动机上的一个节点,对应A,B串的Right集合,已知这些点的最长公共后缀为这个节点的len,暴力的做法可以枚举两个集合的点对(a,b),对于a+2,b+2求lcp更新

    但是复杂度很高,考虑将A,B集合中(a+2)(b+2)这些点按照后缀排序,要求的只有相邻的所属的集合不同的两个后缀的lcp来更新答案

    由于空间的限制,要在parent树自底向上维护set,启发式合并维护信息

    要注意的地方是跨越两个串的地方不能直接丢进set里,会影响rank的比较以及ans的更新

    所以记录一些奇奇怪怪的东西。。这个节点在A,B串后缀出现的位置的最大,最小值(语死早说不清楚)

    代码异常丑陋,还是不要看的好。。

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <set>
      
    #define maxn 500010
      
    using namespace std;
      
    int mark[maxn];
    struct Node{int len, link; map<int, int> nxt;}st[maxn];
    int root, size, last;
    void init(){
        root = size = last = 0;
        st[root].len = 0;
        st[root].link = -1;
    }
    void Extend(int c){
        int p = last, cur = ++ size;
        st[cur].len = st[p].len + 1;
        for(; ~p && st[p].nxt[c] == 0; p = st[p].link)
            st[p].nxt[c] = cur;
        if(p == -1)
            st[cur].link = root;
        else{
            int q = st[p].nxt[c];
            if(st[q].len == st[p].len + 1)
                st[cur].link = q;
            else{
                int clone = ++ size;
                st[clone] = st[q];
                st[clone].len = st[p].len + 1;
                for(; ~p && st[p].nxt[c] == q; p = st[p].link)
                    st[p].nxt[c] = clone;
                st[q].link = st[cur].link = clone;
            }
        }
        last = cur;
    }
      
    int n, m, N, checker;
    char a[maxn], b[maxn];
    int str[maxn];
      
    int sa[maxn], t1[maxn], t2[maxn], c[maxn], rk[maxn], ht[maxn], ST[maxn][20], lg[maxn], stsize;
    int lcp(int x, int y){
        if(x > N || y > N)return 0;
        x = rk[x], y = rk[y];
        if(x > y)swap(x, y);
        y --; int k = lg[y-x+1];
        return min(ST[x][k], ST[y-(1<<k)+1][k]);
    }
      
    /*
    void Get_sa(int n, int m) {
        int *x = wa, *y = wb, *t, i, j, p;
        for(i = 0 ; i < m ; ++ i) ws[i] = 0;
        for(i = 0 ; i < n ; ++ i) ++ ws[x[i] = w[i]];
        for(i = 1 ; i < m ; ++ i) ws[i] += ws[i-1];
        for(i = n-1 ; i >= 0 ; -- i) sa[-- ws[x[i]]] = i;
        for(j = 1, p = 1 ; p < n ; j <<= 1, m = p) {
        //  printf("j = %d, p = %d 
    ", j, p);
            for(i = n-j, p = -1 ; i < n ; ++ i) y[++ p] = i;//puts("NO");
            for(i = 0 ; i < n ; ++ i) if(sa[i]>=j) y[++ p] = sa[i]-j;
            for(i = 0 ; i < n ; ++ i) wv[i] = x[y[i]];
            for(i = 0 ; i < m ; ++ i) ws[i] = 0;
            for(i = 0 ; i < n ; ++ i) ++ ws[wv[i]];
            for(i = 1 ; i < m ; ++ i) ws[i] += ws[i-1];
            for(i = n-1 ; i >= 0 ; -- i) sa[-- ws[wv[i]]] = y[i];
        //  puts("Oh NO");
            for(t = x, x = y, y = t, i = 1, x[sa[0]] = 0, p = 1 ; i < n ; ++ i) {
                x[sa[i]] = cmp(t, sa[i-1], sa[i], j)?p-1:p ++;
            }
        }
        return;
    }
    */
      
    void getsa(int n, int m){
        int *x = t1, *y = t2;
        for(int i = 0; i < m; i ++)c[i] = 0;
        for(int i = 0; i < n; i ++)c[x[i] = str[i]] ++;
        for(int i = 1; i < m; i ++)c[i] += c[i-1];
        for(int i = n-1; ~ i; i --)sa[-- c[x[i]]] = i;
      
        for(int k = 1; k <= n; k <<= 1){
            int p = 0;
            for(int i = n-k; i < n; i ++)y[p ++] = i;
            for(int i = 0; i < n; i ++)if(sa[i] >= k)y[p ++] = sa[i] - k;
              
            for(int i = 0; i < m; i ++)c[i] = 0;
            for(int i = 0; i < n; i ++)c[x[y[i]]] ++;
            for(int i = 1; i < m; i ++)c[i] += c[i-1];
            for(int i = n-1; ~ i; i --)sa[-- c[x[y[i]]]] = y[i];
              
            swap(x, y); x[sa[0]] = 0, p = 1;
            for(int i = 1; i < n; i ++)
                x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k] ? p-1 : p++;
            if(p >= n)break;
            m = p; 
        }
          
        int k = 0;
        for(int i = 0; i < n; i ++)rk[sa[i]] = i;
      
        for(int i = 0; i < n; i ++){
            if(rk[i] == 0){ht[0] = 0; continue;}
            if(k) k --; int j = sa[rk[i]-1];
            while(str[i+k] == str[j+k]) k ++;
            ht[rk[i]] = k;
        }
        for(int i = n; i; i --)sa[i] = sa[i-1] + 1;
        for(int i = 1; i <= n; i ++)rk[sa[i]] = i;
        for(int i = 1; i < n; i ++)ST[i][0] = ht[i];
        stsize = n - 1, lg[0] = -1;
        for(int i = 1; i < n; i ++)lg[i] = lg[i>>1] + 1;
        for(int j = 1; 1<<j <= stsize; j ++)
            for(int i = 1; i+(1<<j)-1 <= stsize; i ++)
                ST[i][j] = min(ST[i][j-1], ST[i+(1<<j-1)][j-1]);
    }
      
    int h[maxn], cnt, ans, Nw, fg;
    struct Edge{int to, nxt;} edge[maxn];
    void addedge(int u, int v){
        edge[++ cnt] = (Edge){v, h[u]}; h[u] = cnt;
    }
      
    struct cmp{
        bool operator ()(const int& x, const int& y){
            return rk[x] < rk[y];
        }
    };
      
    typedef set<int, cmp> se;
    typedef set<int, cmp>::iterator iter;
    vector<int> V[maxn];
    se s[maxn];
      
    inline void cmax(int x, int y){
        if(x > y)swap(x, y);
        if(y <= n || x > n)return;
        if(x <= n ^ y <= n)
            ans = max(ans, Nw + 1 + lcp(x, y));
    }
      
    bool ha[maxn], hb[maxn], fg1, FG1, fg2, FG2, FG3, FG4;
      
    int mx1[maxn], mx2[maxn];
      
    void merge(se& x, se& y, int u, int v){
        if(x.size() < y.size())swap(x, y), swap(V[u], V[v]);
        for(iter it = y.begin(); it != y.end(); it ++){
            iter p = x.upper_bound(*it);
            if(p != x.end())cmax(*p, *it);
            if(p != x.begin())p --, cmax(*p, *it);
        }
          
        FG1 = fg1 = ha[v], FG2 = fg2 = hb[v], FG3 = mx1[v] - Nw >= 1, FG4 = mx2[v] - Nw >= n + 2;
        for(int i = 0; i < V[v].size(); i ++){
            int nw = V[v][i];
            fg1 |= nw <= n, FG1 |= nw < n;
            fg2 |= nw > n && nw <= checker, FG2 |= nw > n && nw < checker;
            if(nw <= n)FG3 |= nw - Nw >= 1; else FG4 |= nw - Nw >= n + 2;
        }
          
        for(int i = 0; i < V[u].size(); i ++){
            int w = V[u][i];
            if(w <= n && fg2){
                ans = max(ans, Nw + (FG2 && ((w == n - 1 || w == n + m))));
                ans = max(ans, Nw + (FG4 && w - Nw != 0 && w - Nw != n + 1));
            }
            if(w > n && fg1){
                ans = max(ans, Nw + (FG1 && (w == n - 1 || w == n + m)));
                ans = max(ans, Nw + (FG3 && w - Nw != 0 && w - Nw != n + 1));
            }
        }
          
        FG1 = fg1 = ha[u], FG2 = fg2 = hb[u], FG3 = mx1[u] - Nw >= 1, FG4 = mx2[u] - Nw >= n + 2;
        for(int i = 0; i < V[u].size(); i ++){
            int nw = V[u][i];
            fg1 |= nw <= n, FG1 |= nw < n;
            fg2 |= nw > n && nw <= checker, FG2 |= nw > n && nw < checker;
            if(nw <= n)FG3 |= nw - Nw >= 1; else FG4 |= nw - Nw >= n + 2;
        }
      
        for(int i = 0; i < V[v].size(); i ++){
            int w = V[v][i];
            if(w <= n && fg2){
                ans = max(ans, Nw + (FG2 && ((w == n - 1 || w == n + m))));
                ans = max(ans, Nw + (FG4 && w - Nw != 0 && w - Nw != n + 1));
            }
            if(w > n && fg1){
                ans = max(ans, Nw + (FG1 && (w == n - 1 || w == n + m)));
                ans = max(ans, Nw + (FG3 && w - Nw != 0 && w - Nw != n + 1));
            }
        }
          
        for(int i = 0; i < V[v].size(); i ++)
            V[u].push_back(V[v][i]);
          
        for(iter it = y.begin(); it != y.end(); it ++)
            x.insert(*it);
        V[v].clear(), y.clear();
    }
      
    void dfs(int u){
        if(~mark[u]){
            if((mark[u] > n+1 && mark[u]+2 <= checker) || mark[u]+2 <= n){
                s[u].insert(mark[u]+2);
                ha[u] |= mark[u] <= n;
                hb[u] |= mark[u] > n;
            }
            else V[u].push_back(mark[u]);
            if(mark[u] <= n)mx1[u] = max(mx1[u], mark[u]);
            else mx2[u] = max(mx2[u], mark[u]);
        }
        for(int i = h[u]; i; i = edge[i].nxt){
            int v = edge[i].to;
            dfs(v);
            Nw = st[u].len;
            merge(s[u], s[v], u, v);
            ha[u] |= ha[v];
            hb[u] |= hb[v];
            mx1[u] = max(mx1[u], mx1[v]);
            mx2[u] = max(mx2[u], mx2[v]);
        }
    }
      
    int nd[10];
      
    int main(){
        init();ans = 1;
        scanf("%s%s", a + 1, b + 1);
        n = strlen(a + 1), m = strlen(b + 1);
          
        for(int i = 1; i <= n; i ++)Extend(a[i] - 'a'); Extend(27);
        for(int i = 1; i <= m; i ++)Extend(b[i] - 'a');
          
        for(int i = 1; i <= size; i ++)addedge(st[i].link, i);
        memset(mark, -1, sizeof mark); int cur = root; mark[root] = 0;
        for(int i = 1; i <= n; i ++)cur = st[cur].nxt[a[i] - 'a'], mark[cur] = i;
        cur = st[cur].nxt[27];
        for(int i = 1; i <= m; i ++)cur = st[cur].nxt[b[i] - 'a'], mark[cur] = i+n+1;
          
        N = 0, checker = n + m + 1;
        for(int i = 1; i <= n; i ++)str[N ++] = a[i] - 'a' + 1; str[N ++] = 27;
        for(int i = 1; i <= m; i ++)str[N ++] = b[i] - 'a' + 1;
        getsa(n+m+2, 30);
          
        dfs(0);
        printf("%d
    ", ans);
        return 0;
    }
    

      

    给时光以生命,而不是给生命以时光。
  • 相关阅读:
    C#下给数字前面补0的方法
    Notepad++ xml 文件不能语法着色的问题解决
    excel 技巧
    编译时报警 implicit declaration of function
    配置ASP.NET平台时遇到的“访问IIS元数据库失败”解决方案
    用360安全卫士批量本地快速给系统打补丁【转贴】
    新雨情系统随笔
    我的开发博客开通了
    JQuery资料
    IGNORE_DUP_KEY = OF的作用
  • 原文地址:https://www.cnblogs.com/Candyouth/p/5596918.html
Copyright © 2011-2022 走看看