zoukankan      html  css  js  c++  java
  • POJ 1743 Musical Theme【SAM】

    POJ1743 Musical Theme

    要找长度(ge 5)且出现次数(ge 2)并且第一次出现和最后一次出现不重叠的最长子串。
    题目条件中,如果对于两个串,在一个串的每个数上都加上相同的数之后可以得到另一个串,那么这个两个串可以被是相同的。
    首先我们先得到差分数组,然后要求的就是差分数组中长度(ge 4)且出现次数(ge 2)并且第一次出现和最后一次出现不重叠的最长子串
    我们需要知道的是每个等价类中终点的最左端和最右端的位置,即((firstpos,lastpos)),每次新加入一个字符所得到的等价类其(firstpos)(lastpos)必然为当前的下标,当构造完(SAM)之后,由于(parent)树的性质,(link[u])所表示的等价类必然是(u)所表示的等价类的后缀,所以可以得到:(lastpos[u] = max_{vin children} lastpos[v])其中(v)(u)(parent)树中的儿子,而(firstpos)必然一直保持不变。
    可以用拓扑排序然后倒序遍历来代替建(parent)树然后(dfs),拓扑排序即为按(len)排序,用基数排序即可

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<string>
    #include<algorithm>
    #include<stack>
    using namespace std;
    void ____(){ ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); }
    const int MAXN = 1e5+7;
    int n,A[MAXN];
    struct SAM{
        int len[MAXN],link[MAXN],firstpos[MAXN],lastpos[MAXN],ch[MAXN][180],tot,last,cnt[MAXN],c[MAXN],sa[MAXN];
        void init(){ link[tot = last = cnt[0] = len[0] = 0] = -1; memset(ch[0],0,sizeof(ch[0])); }
        void extend(int x){
            int np = ++tot, p = last; firstpos[tot] = lastpos[tot] = len[tot] = len[last] + 1;
            memset(ch[tot],0,sizeof(ch[tot])); cnt[tot] = 1;
            while(p!=-1 and !ch[p][x]){
                ch[p][x] = np;
                p = link[p];
            }
            if(p==-1) link[np] = 0;
            else{
                int q = ch[p][x];
                if(len[p]+1==len[q]) link[np] = q;
                else{
                    int clone = ++tot;
                    cnt[clone] = 0;
                    firstpos[clone] = firstpos[q];
                    lastpos[clone] = lastpos[q];
                    len[clone] = len[p] + 1;
                    for(int i = 0; i < 180; i++) ch[clone][i] = ch[q][i];
                    link[clone] = link[q];
                    while(p!=-1 and ch[p][x]==q){
                        ch[p][x] = clone;
                        p = link[p];
                    }
                    link[np] = link[q] = clone;
                }
            }
            last = np;
        }
        int solve(){
            for(int i = 0; i <= n; i++) c[i] = 0;
            for(int i = 0; i <= tot; i++) c[len[i]]++;
            for(int i = 1; i <= n; i++) c[i] += c[i-1];
            for(int i = tot; i >= 0; i--) sa[c[len[i]]--] = i;
            int ret = 0;
            for(int i = tot+1; i >= 1; i--){            //这里要注意,基数排序的时候是0~tot,所以排名最后的是tot+1
                int u = sa[i];
                cnt[link[u]] += cnt[u];
                lastpos[link[u]] = max(lastpos[link[u]],lastpos[u]);
                ret = max(ret,min(len[u] + 1,lastpos[u]-firstpos[u]));
            }
            if(ret<5) ret = 0;
            return ret;
        }
    }sam;
    void solve(){
        for(int i = 1; i <= n; i++) scanf("%d",&A[i]);
        for(int i = 1; i < n; i++) A[i] = A[i+1] - A[i] + 88;
        sam.init(); for(int i = 1; i < n; i++) sam.extend(A[i]);
        printf("%d
    ",sam.solve());
    }
    int main(){
        while(scanf("%d",&n)!=EOF and n) solve(); 
        return 0;
    }
    
  • 相关阅读:
    Find the capitals
    Area of a Circle
    SequenceSum
    使用Eclipse设定Android开发环境
    hdu 1290 竭诚为杭州电礼物50周年
    oracle connect by 说明
    CSS截取字符串,额外的文本显示以省略号
    动态规划——背包问题
    【MySQL笔记】mysql来源安装/配置步骤和支持中国gbk/gb2312编码配置
    博客搬到了http://xianglong.me
  • 原文地址:https://www.cnblogs.com/kikokiko/p/12700373.html
Copyright © 2011-2022 走看看