• 学习系列


    字符串算法有哪些呢???Tire,BM,KMP,AC自动机,后缀数组,后缀自动机,RK,Shift-And/Or,Manacher.....

    ™这么这么多啊!!!

    也只能慢慢学了。。。【后期:好多算法都是没用的鬼。。

    接下来的题是按我做题顺序来排的,难度的话我就不理了(`・ω・´)


    先是BZOJ。。。

    BZOJ 2434: [NOI2011]阿狸的打字机

    第一道字符串就做这道简直大丈夫!

    先建棵ACTree和FailTree,保存每个字符串的末节点位置。

    然后从树根一步一步走,根至当前节点的字符串就是当前打字机内的字符串,一边走一边离线查询。

    对于每个查询(x,y)在查到s[y]的末尾节点的时候开始计算,用DFS序思想和树状数组求s[x]的末尾节点的Fail子树中包含了几个s[y]的节点,这就是答案了。

    当时AC自动机不会,FailTree不会,后缀数组不会,DFS序没想到。。。QAQ

    #include <algorithm>
    #include <cstdio>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <vector>
    #include <queue>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 123456
    #define MAX 1037471823
    
    using namespace std;
    
    struct node 
    { 
        int x, y, n; 
        bool operator < (const node &k) const { return x < k.x; };
    } e[MS]; int ec, fir[MS];
    int c[MS], r[MS][26], f[MS], h[MS], tc, ss[MS], ds[MS], dt[MS], k[MS];
    queue<int> p;
    int n, m, x, y, now, nq;
    char s[MS];
    
    void DFS(int x)
    {
        int o = fir[x]; ds[x] = ++now;
        while (o) { DFS(e[o].y); o = e[o].n; }
        dt[x] = now;
    }
    
    inline void Add(int x, int z)
        { int o = x; while (o<=tc+1) k[o]+=z, o = o+(o&(-o));  }
    
    inline int Qsum(int x)
    {
        int o = x, ans=0; while (o) ans+=k[o], o = o-(o&(-o));  
        return ans;
    }
    
    inline void Query(int x)
    {
        while (e[nq].x == x)
            { int y=e[nq].y; e[nq].y = Qsum(dt[ss[y]]) - Qsum(ds[ss[y]]-1); nq++; }
    }
        
    int main()
    {
        scanf("%s", s); int l=strlen(s); f[0] = -1;
        rep(i, 0, l-1) 
            if (s[i]!='P' && s[i]!='B') 
                { if (!r[now][s[i]-'a']) tc++, r[now][s[i]-'a']=tc, h[tc]=now, c[tc]=s[i]-'a'; now=r[now][s[i]-'a']; }
            else if (s[i]=='P') ss[++n] = now; 
            else now = h[now];
        rep(i, 0, tc) f[i] = -1; p.push(0);
        while (!p.empty())
        {
            x = p.front(); p.pop();
            rep(i, 0, 25) if (r[x][i])
            {
                int fo = f[x]; 
                while (fo >= 0)
                    { if (r[fo][i]) break; else fo = f[fo]; }
                if (fo < 0) f[r[x][i]] = 0; else f[r[x][i]] = r[fo][i];
                p.push(r[x][i]);
            }
        }
        down(i, tc, 1) e[i].y = i, e[i].n = fir[f[i]], fir[f[i]] = i; now = 0; DFS(0);
        rep(i, 1, tc) fir[i] = 0;
        scanf("%d", &m);
        rep(i, 1, m)
            { scanf("%d%d", &x, &y); e[i].x = y, e[i].y = x, e[i].n = i; }
        sort(e+1, e+1+m);
        now=n=0; nq=1; rep(i, 0, l-1) 
            if (s[i]!='P' && s[i]!='B') { now=r[now][s[i]-'a']; Add(ds[now], 1); }
            else if (s[i]=='P') Query(++n); else { Add(ds[now], -1); now = h[now]; }
        rep(i, 1, m) e[i].x = e[i].n; sort(e+1, e+1+m); rep(i, 1, m) printf("%d
    ", e[i].y);
        return 0;
    }
    View Code

    BZOJ 3172: [TJOI2013]单词

    依旧FailTree搞,建好之后就遍历+统计,然后s[i]的出现次数就是末尾节点的Fail子树所包含的其他串的节点个数(重复出现也要算)。

    #include <algorithm>
    #include <cstdio>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <vector>
    #include <queue>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 1234567
    #define MAX 1037471823
    
    using namespace std;
    
    struct node { int y, z; } e[MS]; int fir[MS];
    int n, c[MS], k[MS], r[MS][26], f[MS], tc, ss[MS], x;
    queue<int> q;
    char s[MS];
    
    void Add(int n)
    {
        int o = 0, l = strlen(s);
        rep(i, 0, l-1) 
        {
            if (!r[o][s[i]-'a']) tc++, r[o][s[i]-'a'] = tc, c[tc] = s[i]-'a';
            o = r[o][s[i]-'a'], k[o]++;
        }
        ss[n] = o;
    }
    
    void DFS(int x)
    {
        int o = fir[x];
        while (o)
            { DFS(e[o].y); k[x] += k[e[o].y]; o = e[o].z; }
    }
        
    int main()
    {
        scanf("%d", &n);
        rep(i, 1, n) { scanf("%s", s); Add(i); }
        q.push(0); f[0] = -1;
        while (!q.empty())
        {
            x = q.front(); q.pop();
            rep(i, 0, 25) if (r[x][i])
            {
                int fo = f[x]; 
                while (fo >= 0 && !r[fo][i]) fo = f[fo];
                if (fo < 0) f[r[x][i]] = 0; else f[r[x][i]] = r[fo][i]; q.push(r[x][i]);
            }
        }
        rep(i, 1, tc) e[i].y = i, e[i].z = fir[f[i]], fir[f[i]] = i; DFS(0);
        rep(i, 1, n) printf("%d
    ", k[ss[i]]);
        return 0; 
    }
    View Code

    BZOJ 1030: [JSOI2007]文本生成器

    数位DP+AC自动机,没了。

    #include <queue>
    #include <algorithm>
    #include <fstream>
    #include <iostream>
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 6789
    #define MAX 1037471823
    #define Q 10007
    
    using namespace std;
    
    struct node{ int y, n; }e[MS]; int fir[MS];
    int n, m, c[MS], r[MS][26], f[MS], tc, dp[123][MS], ans, x, y;
    bool b[MS]; char s[MS];
    queue <int> q;
    
    void Add()
    {
        int l = strlen(s), o = 0;
        rep(i, 0, l-1)
            { if (!r[o][s[i]-'A']) tc++, r[o][s[i]-'A'] = tc, c[tc] = s[i]-'A'; o = r[o][s[i]-'A']; }
        b[o] = true;
    }
    
    void DFS(int x)
    {
        int o = fir[x]; b[x] = true;
        while (o) { DFS(e[o].y); o = e[o].n; }
    }
    
    /* void Query(int x, int n)
    {
        if (x == 1) rep(i, 0, tc) rep(j, 0, tc) dp[n][i][j] = k[i][j] % Q; 
        else if (x % 2==1) 
        {
            Query(x-1, n+1);
            rep(i, 0, tc) rep(j, 0, tc) rep(o, 0, tc) dp[n][i][j] += dp[n+1][i][o] * k[o][j], dp[n][i][j]%=Q;
        }
        else
        {
            Query(x/2, n+1);
            rep(i, 0, tc) rep(j, 0, tc) rep(o, 0, tc) dp[n][i][j] += dp[n+1][i][o] * dp[n+1][o][j], dp[n][i][j]%=Q;
        }
    } */
    
    int Mult(int x)
    {
        if (x == 1) return 26; else if (x % 2 == 1) return (Mult(x-1)*26)%Q; else { int a = Mult(x/2); return (a*a)%Q; }
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        rep(i, 1, n) { scanf("%s", s); Add(); }
        q.push(0); f[0] = -1;
        while (!q.empty())
        {
            x = q.front(); q.pop();
            rep(i, 0, 25) if (r[x][i])
            {
                y = f[x];
                while (y >= 0 && !r[y][i]) y = f[y];
                if (y < 0) f[r[x][i]] = 0; else f[r[x][i]] = r[y][i]; q.push(r[x][i]);
            }
        }
        rep(i, 1, tc) e[i].y = i, e[i].n = fir[f[i]], fir[f[i]] = i;
        rep(i, 1, tc) if (b[i]) DFS(i);
        dp[0][0] = 1; 
        rep(k, 0, m-1)
            rep(i, 0, tc) if (!b[i] && dp[k][i]) 
            {
                rep(j, 0, 25) 
                {
                    y = i; 
                    while (y >= 0 && !r[y][j]) y = f[y];
                    if (y < 0) dp[k+1][0]+=dp[k][i], dp[k+1][0]%=Q; else dp[k+1][r[y][j]]+=dp[k][i], dp[k+1][r[y][j]]%=Q;
                }
            }
        rep(i, 0, tc) if (!b[i]) ans = (ans + dp[m][i])% Q;
        /* Query(m, 1);
        rep(i, 0, tc) if (!b[i]) ans = (ans + dp[1][0][i])%Q; */
        ans = Mult(m) - ans; while (ans < 0) ans += Q;
        printf("%d
    ", ans);
        return 0;
    }
    View Code

    BZOJ 2754: [SCOI2012]喵星球上的点名

    建AC自动机,然后对于每次询问就查找询问串的Fail子树所包含那些字符串的节点,然后被点到名字的就次数+1。

    结果AC是AC了,时间跑出了个11s。。。

    吐血。。。

    那么我们换成后缀数组来做:

    把所有出现过的串全部连成一串(中间插字符),然后后缀一遍,接着从上到下找,对于以询问串作为前缀的后缀s[i],我们就找出所有和s[i]的公共前缀长度大于询问串长度的后缀,然后统计去重。。。

    嗯AC,2s

    #include <cstdlib>
    #include <cstdio>
    #include <algorithm>
    #include <fstream>
    #include <iostream>
    #include <cmath>
    #include <set>
    #include <queue>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 345678
    #define MAX 1073741823
    
    using namespace std;
    
    struct node
    {
        int x, y, s;
        bool operator < (const node &k) const { return x < k.x || (x == k.x && y < k.y); }
    } q[MS];
    int n, m, x, y, l, s[MS], k[MS], sa[MS], r[MS], ss[MS], c1[MS], c2[MS], h[MS], b[MS];
    
    int main()
    {
        scanf("%d%d", &n, &m);
        rep(i, 1, n*2) 
            { scanf("%d", &x); rep(j, 1, x) { scanf("%d", &s[++l]); k[l] = (i+1)/2; } s[++l] = -1; }
        rep(i, 1, m) 
            { k[l+1] = -i; scanf("%d", &ss[i]); rep(j, 1, ss[i]) scanf("%d", &s[++l]); s[++l] = -1; }
        x = 1; rep(i, 1, l) r[i] = s[i];
        while (x <= l)
        {
            rep(i, 1, l) q[i].x = r[i], q[i].y = i+x>l?0:r[i+x], q[i].s = i;
            sort(q+1, q+1+l);
            y = r[q[1].s] = 1;
            rep(i, 2, l) if ((q[i].x != q[i-1].x) || (q[i].y != q[i-1].y)) r[q[i].s] = ++y; else r[q[i].s] = y;
            if (y == l) break; else x *= 2;
        }
        rep(i, 1, l) sa[r[i]] = i;
        x = 0; rep(i, 1, l)
        {
            if (x) x--;
            int j = sa[r[i]-1];
            while (s[i+x]==s[j+x]) x++;
            h[r[i]] = x;
        }
        rep(i, 1, l) if (k[i] < 0)
        {
            y = -k[i];
            x = r[i]; 
            while (h[x] >= ss[y]) 
            { 
                if (k[sa[x-1]] > 0 && b[k[sa[x-1]]] != y) 
                    b[k[sa[x-1]]] = y, c1[k[sa[x-1]]]++, c2[y]++; 
                x--; 
            }
            x = r[i]+1; 
            while (h[x] >= ss[y]) 
            { 
                if (k[sa[x]] > 0 && b[k[sa[x]]] != y) 
                    b[k[sa[x]]] = y, c1[k[sa[x]]]++, c2[y]++; 
                x++; 
            }
        }
        rep(i, 1, m) printf("%d
    ", c2[i]);
        rep(i, 1, n) printf("%d%c", c1[i], i==n?'
    ':' ');
        return 0;
    }
    View Code

     


    然后Ecstasy大神扔了份后缀数组论文的pdf给我。。。

    POJ 1743: Musical Theme

    求不重叠·最长·重复·子串的长度。

    二分答案+分组统计(后缀数组最重要最常用的思想),判断组内Sa的极差。

    #include <cstdio>
    #include <fstream>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 23456
    #define MAX 1073741823
    
    using namespace std;
    
    struct node
    {
        int x, y, z;
        bool operator < (const node &k) const { return x < k.x || (x == k.x && y < k.y); }
    } q[MS];
    int n, s[MS], h[MS], sa[MS], rk[MS], a, p, l, r;
    
    bool Check(int k)
    {
        int bs = 0, ss = 0;
        rep(i, 1, n) 
            if (h[i] < k) if (bs - ss >= k) return true; else bs = ss = sa[i]; else
            { if (ss > sa[i]) ss = sa[i]; if (bs < sa[i]) bs = sa[i]; }
        if (bs - ss >= k) return true; else return false; 
    }
    
    int main()
    {
        scanf("%d", &n);
        while (n)
        {
            rep(i, 1, n) scanf("%d", &s[i]);
            rep(i, 1, n-1) s[i] = s[i+1] - s[i]; n--; 
            rep(i, 1, n) rk[i] = s[i];
            p = 1; while (p <= n)
            {
                rep(i, 1, n) q[i].x = rk[i], q[i].y = i+p>n ? 0 : rk[i+p], q[i].z = i; 
                sort(q+1, q+1+n);
                a = 0; rep(i, 1, n) if (q[i].x != q[i-1].x || q[i].y != q[i-1].y) rk[q[i].z] = ++a; 
                    else rk[q[i].z] = a;
                if (a == n) break; else p*=2;
            }
            rep(i, 1, n) sa[rk[i]] = i;
            a = 0; rep(i, 1, n)
            {
                if (a) a--; p = sa[rk[i]-1];
                while (s[i+a] == s[p+a]) a++; h[rk[i]] = a;
            }
            l = 0, r = n/2; while (l != r) if (Check((l+r)/2+1)) l = (l+r)/2+1; else r = (l+r)/2;
            if (l < 4) printf("0
    "); else printf("%d
    ", l+1); scanf("%d", &n);
        }
        return 0;
    }
    View Code

    POJ 3261: Milk Patterns

    求可重叠·最长·至少重复K次·子串的长度。

    依旧二分答案+分组统计,判断组内后缀的个数。

    #include <cstdio>
    #include <fstream>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 23456
    #define MAX 1073741823
    
    using namespace std;
    
    struct node
    {
        int x, y, z;
        bool operator < (const node &k) const { return x < k.x || (x == k.x && y < k.y); }
    } q[MS];
    int n, s[MS], h[MS], sa[MS], rk[MS], a, p, l, r, c;
    
    bool Check(int k)
    {
        int a = 0;
        rep(i, 1, n+1) if (h[i] < k) { if (i - a >= c) return true; else a = i; }
        return false;
    }
    
    int main()
    {
        scanf("%d%d", &n, &c);
        rep(i, 1, n) scanf("%d", &s[i]);
        rep(i, 1, n) rk[i] = s[i];
        p = 1; while (p <= n)
        {
            rep(i, 1, n) q[i].x = rk[i], q[i].y = i+p>n ? 0 : rk[i+p], q[i].z = i; sort(q+1, q+1+n);
            a = 0; rep(i, 1, n) if (q[i].x != q[i-1].x || q[i].y != q[i-1].y) rk[q[i].z] = ++a; else rk[q[i].z] = a;
            if (a == n) break; else p*=2;
        }
        rep(i, 1, n) sa[rk[i]] = i;
        a = 0; rep(i, 1, n)
        {
            if (a) a--; p = sa[rk[i]-1];
            while (s[p+a] == s[i+a]) a++; h[rk[i]] = a;
        }
        l = 0, r = n+1; while (l!=r) if (Check((l+r)/2+1)) l = (l+r)/2+1; else r = (l+r)/2;
        printf("%d
    ", l);
        return 0;
    }
    View Code

    SPOJ DISUBSTR: Distinct Substrings

    求不相同·子串的个数。

    Ans=∑(n-sa[k]+1-height[k])(1..k..n)

    #include <cstdio>
    #include <fstream>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 2345
    #define MAX 1073741823
    
    using namespace std;
    
    struct node
    {
        int x, y, z;
        bool operator < (const node &k) const { return x < k.x || (x == k.x && y < k.y); }
    } q[MS];
    int t, n, sa[MS], rk[MS], h[MS], a, p, ans;
    char s[MS];
    
    int main()
    {
        scanf("%d", &t);
        while (t--)
        {
            scanf("%s", s); n = strlen(s);
            rep(i, 1, n) rk[i] = s[i-1];
            p = 1; while (p <= n)
            {
                rep(i, 1, n) q[i].x = rk[i], q[i].y = i+p>n?0:rk[i+p], q[i].z = i; sort(q+1, q+1+n);
                a = 0; rep(i, 1, n) if (q[i].x != q[i-1].x || q[i].y != q[i-1].y) rk[q[i].z] = ++a; else rk[q[i].z] = a;
                if (a == n) break; else p*=2;
            }
            rep(i, 1, n) sa[rk[i]] = i;
            a = 0; rep(i, 1, n)
            {
                if (a) a--; p = sa[rk[i]-1];
                while (s[p+a-1] == s[i+a-1]) a++; h[i] = a;
            }
            rep(i, 1, n) ans -= h[i];
            ans += (n*n+n)/2; printf("%d
    ", ans); ans = 0;
        }
        return 0;
    }
    View Code

    SPOJ SUBST1: New Distinct Substrings

    和上一道一样咯

    #include <cstdio>
    #include <fstream>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 56789
    #define MAX 1073741823
    
    using namespace std;
    
    struct node
    {
        int x, y, z;
        bool operator < (const node &k) const { return x < k.x || (x == k.x && y < k.y); }
    } q[MS];
    int t, n, sa[MS], rk[MS], a, p;
    long long ans;
    char s[MS];
    
    int main()
    {
        scanf("%d", &t);
        while (t--)
        {
            scanf("%s", s); n = strlen(s); ans = n; ans = (ans*n+n)/2;
            rep(i, 1, n) rk[i] = s[i-1];
            p = 1; while (p <= n)
            {
                rep(i, 1, n) q[i].x = rk[i], q[i].y = i+p>n?0:rk[i+p], q[i].z = i; sort(q+1, q+1+n);
                a = 0; rep(i, 1, n) if (q[i].x != q[i-1].x || q[i].y != q[i-1].y) rk[q[i].z] = ++a; else rk[q[i].z] = a;
                if (a == n) break; else p*=2;
            }
            rep(i, 1, n) sa[rk[i]] = i;
            a = 0; rep(i, 1, n)
            {
                if (a) a--; p = sa[rk[i]-1];
                while (s[p+a-1] == s[i+a-1]) a++; ans -= a;
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
    View Code

    Ural 1297: Palindrome

    最长回文子串,经典!

    翻转连接后就变成了求最长公共子串。

    #include <cstdio>
    #include <fstream>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 2345
    #define MAX 1073741823
    
    using namespace std;
    
    struct node
    {
        int x, y, z;
        bool operator < (const node &k) const { return x < k.x || (x == k.x && y < k.y); }
    } q[MS];
    int t, n, sa[MS], rk[MS], h[MS], k[MS][19], a, p, ans, ans2, x;
    char s[MS];
    
    int rmq(int x, int y)
    {
        if (x > y) a = x, x = y, y = a; x++;
        p = int(log(y-x+1)/log(2)); a = 1; rep(i, 1, p) a *= 2; 
        return min(k[x][p], k[y-a+1][p]);
    }
    
    int main()
    {
        scanf("%s", s); n = strlen(s);
        s[n] = ' '; rep(i, 1, n) s[i+n] = s[n-i]; n = n*2+1;
        rep(i, 1, n) rk[i] = s[i-1];
        p = 1; while (p <= n)
        {
            rep(i, 1, n) q[i].x = rk[i], q[i].y = i+p>n?0:rk[i+p], q[i].z = i; sort(q+1, q+1+n);
            a = 0; rep(i, 1, n) if (q[i].x != q[i-1].x || q[i].y != q[i-1].y) rk[q[i].z] = ++a; else rk[q[i].z] = a;
            if (a == n) break; else p*=2;
        }
        rep(i, 1, n) sa[rk[i]] = i;
        a = 0; rep(i, 1, n)
        {
            if (a) a--; p = sa[rk[i]-1];
            while (s[p+a-1] == s[i+a-1]) a++; h[rk[i]] = a;
        }
        rep(i, 1, n) k[i][0] = h[i];
        a = 1; rep(j, 1, int(log(n)/log(2)))
            { rep(i, 1, n-a) k[i][j] = min(k[i][j-1], k[i+a][j-1]); a*=2; }
        rep(i, 1, n/2) 
            { x = rmq(rk[i], rk[n-i+1]); if (ans < x*2-1) ans = x*2-1, ans2 = i-x+1; }
        rep(i, 2, n/2) 
            { x = rmq(rk[i], rk[n-i+2]); if (ans < x*2) ans = x*2, ans2 = i-x; }
        rep(i, ans2, ans2+ans-1) printf("%c", s[i-1]); printf("
    ");
        return 0;
    }
    View Code

    POJ 2406: Power Strings

    给定一个字符串L,已知这个字符串是由某个字符串S重复R次而得到的,求R的最大值。

    从小到大枚举S的长度K,然后判断L能否整除K,且Suf[1]与Suf[1+k]的公共前缀长度是否等于L-k

    #include <cstdio>
    #include <fstream>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 1234567
    #define MAX 1073741823
    
    using namespace std;
    
    int n, f[MS], a;
    char s[MS];
    
    int main()
    {
        scanf("%s", s);
        while (s[0] != '.')
        {
            n = strlen(s);
            f[0] = -1; rep(i, 2, n)
            {
                a = f[i-1]; while (a >= 0 && s[a] != s[i-1]) a = f[a];
                if (a < 0) f[i] = 0; else f[i] = a+1;
            }
            if (n%(n-f[n])==0) printf("%d
    ", n/(n-f[n])); else printf("1
    "); scanf("%s", s);
        }
        return 0;
    }
    View Code

    POJ 3693: Maximum repetition substring

    给定一个字符串,求重复次数最多的连续重复子串。

    这题还是得看论文的解释。。。我这题貌似弄最久。。。WA了7次

    #include <cstdio>
    #include <fstream>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 123456
    #define MAX 1073741823
    
    using namespace std;
    
    struct node
    {
        int x, y, z;
        bool operator < (const node &k) const { return x < k.x || (x == k.x && y < k.y); }
    } q[MS];
    int n, rk[MS], sa[MS], h[MS], k[MS][20], rec[MS], o, m, a, p, l, T, t, ans, pd;
    char s[MS];
    
    int rmq(int x, int y)
    {
        int a, p;
        if (x > y) a = x, x = y, y = a; x++;
        a = 1, p = 0; while (a*2 <= y-x+1) a*=2, p++; 
        return min(k[x][p], k[y-a+1][p]);
    }
    
    int main()
    {
        scanf("%s", s);
        while (s[0]!='#')
        {
            n = strlen(s);
            rep(i, 1, n) rk[i] = s[i-1];
            p = 1; while (p <= n)
            {
                rep(i, 1, n) q[i].x = rk[i], q[i].y = i+p>n ? 0 : rk[i+p], q[i].z = i; sort(q+1, q+1+n);
                a = 0; rep(i, 1, n) if (q[i].x != q[i-1].x || q[i].y != q[i-1].y) rk[q[i].z] = ++a; else rk[q[i].z] = a;
                if (a == n) break; else p *= 2;
            }
            rep(i, 1, n) sa[rk[i]] = i;
            a = 0; rep(i, 1, n)
            {
                if (a) a--; p = sa[rk[i]-1];
                while (s[p+a-1] == s[i+a-1]) a++; h[rk[i]] = a; 
            }
            rep(i, 1, n) k[i][0] = h[i];
            a = 1, p = 0; while (a*2 <= n) a*=2, p++;
            a = 1; rep(j, 1, p)
                { rep(i, 1, n-a) k[i][j] = min(k[i][j-1], k[i+a][j-1]); a*=2; }
            ans = 1;
            rep(l, 1, n-1)
            {
                a = 1;
                while (a+l <= n) if (s[a-1] == s[a+l-1])
                {
                    m = rmq(rk[a], rk[a+l]); 
                    p = m/l+1, t = a-(l-m%l); 
                    if (t>0 && m%l!=0 && rmq(rk[t], rk[t+l])>=m) p++;
                    if (p > ans) ans = p, o = 1, rec[o] = l;
                    else if (p == ans && rec[o] != l) rec[++o] = l;
                    a += l;
                } else a+=l;
            }
            if (ans == 1) { o = n-1; rep(i, 1, o) rec[i] = i; }
            pd = 0;
            rep(i, 1, n) if (!pd) rep(j, 1, o)
                { if (rmq(i, rk[sa[i]+rec[j]]) >= (ans-1)*rec[j]) { a = sa[i]; p = rec[j]; pd++; break; } }
            else break;
            printf("Case %d: ", ++T);
            rep(i, a, a+p*ans-1) printf("%c", s[i-1]); printf("
    ");
            scanf("%s", s);
        }
        return 0;
    }
    View Code

    SPOJ REPEATS: Repeats

    和上一道一样咯

    #include <cstdio>
    #include <fstream>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 56789
    #define MAX 1073741823
    
    using namespace std;
    
    struct node
    {
        int x, y, z;
        bool operator < (const node &k) const { return x < k.x || (x == k.x && y < k.y); }
    } q[MS];
    int n, rk[MS], sa[MS], h[MS], k[MS][20], m, a, p, l, T, t, ans, pd;
    char s[MS];
    
    int rmq(int x, int y)
    {
        int a, p;
        if (x > y) a = x, x = y, y = a; x++;
        a = 1, p = 0; while (a*2 <= y-x+1) a*=2, p++; 
        return min(k[x][p], k[y-a+1][p]);
    }
    
    int main()
    {
        scanf("%d", &T);
        while (T--)
        {
            scanf("%d", &n);
            rep(i, 1, n) { s[i-1] = 0; while (s[i-1] < 'a' || s[i-1] > 'z') scanf("%c", &s[i-1]); }
            rep(i, 1, n) rk[i] = s[i-1];
            p = 1; while (p <= n)
            {
                rep(i, 1, n) q[i].x = rk[i], q[i].y = i+p>n ? 0 : rk[i+p], q[i].z = i; sort(q+1, q+1+n);
                a = 0; rep(i, 1, n) if (q[i].x != q[i-1].x || q[i].y != q[i-1].y) rk[q[i].z] = ++a; else rk[q[i].z] = a;
                if (a == n) break; else p *= 2;
            }
            rep(i, 1, n) sa[rk[i]] = i;
            a = 0; rep(i, 1, n)
            {
                if (a) a--; p = sa[rk[i]-1];
                while (s[p+a-1] == s[i+a-1]) a++; h[rk[i]] = a; 
            }
            rep(i, 1, n) k[i][0] = h[i];
            a = 1, p = 0; while (a*2 <= n) a*=2, p++;
            a = 1; rep(j, 1, p)
                { rep(i, 1, n-a) k[i][j] = min(k[i][j-1], k[i+a][j-1]); a*=2; }
            ans = 1;
            rep(l, 1, n-1)
            {
                a = 1;
                while (a+l <= n) if (s[a-1] == s[a+l-1])
                {
                    m = rmq(rk[a], rk[a+l]); 
                    p = m/l+1, t = a-(l-m%l); 
                    if (t>0 && m%l!=0 && rmq(rk[t], rk[t+l])>=m) p++;
                    if (p > ans) ans = p;
                    a += l;
                } else a += l;
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    View Code

    Ural 1517: Freedom of Choice

    最长公共子串。连起来,没了。

    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <iostream>
    #include <fstream>
    #include <cmath>
    #include <algorithm>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 234567
    #define MAX 1073741823
    
    using namespace std;
    
    struct node
    {
        int x, y, z;
        bool operator < (const node &k) const { return x<k.x || (x==k.x && y<k.y); }
    } q[MS];
    int n, l, a, p, rk[MS], sa[MS], h[MS], ans;
    char s[MS], s1[MS];
    
    int main()
    {
        scanf("%d", &l);
        scanf("%s", s1); rep(i, 1, l) s[i-1] = s1[i-1]; s[l] = ' '; n = l+1;
        scanf("%s", s1); rep(i, 1, l) s[n+i-1] = s1[i-1]; n += l;
        rep(i, 1, n) rk[i] = s[i-1];
        p = 1; while (p <= n)
        {
            rep(i, 1, n) q[i].x = rk[i], q[i].y = i+p>n ? 0 : rk[i+p], q[i].z = i; sort(q+1, q+1+n);
            a = 0; rep(i, 1, n) if (q[i].x != q[i-1].x || q[i].y != q[i-1].y) rk[q[i].z] = ++a; else rk[q[i].z] = a;
            if (a == n) break; else p *= 2;
        }
        rep(i, 1, n) sa[rk[i]] = i;
        a = 0; rep(i, 1, n)
        {
            if (a) a--; p = sa[rk[i]-1];
            while (s[p+a-1] == s[i+a-1]) a++; h[rk[i]] = a;
        }
        l = sa[1]; rep(i, 3, n) if ((sa[i-1] < l && sa[i] > l) || (sa[i-1] > l && sa[i] < l)) ans = max(ans, h[i]);
        rep(i, 3, n) if (((sa[i-1] < l && sa[i] > l) || (sa[i-1] > l && sa[i] < l)) && ans == h[i]) 
        {
            rep(j, 1, ans) printf("%c", s[sa[i]+j-2]);
            return 0;
        }
        return 0;
    }
    View Code

    POJ 2774: Long Long Message

    也是最长公共子串。

    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <iostream>
    #include <fstream>
    #include <cmath>
    #include <algorithm>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 234567
    #define MAX 1073741823
    
    using namespace std;
    
    struct node
    {
        int x, y, z;
        bool operator < (const node &k) const { return x<k.x || (x==k.x && y<k.y); }
    } q[MS];
    int n, l, a, p, rk[MS], sa[MS], h[MS], ans;
    char s[MS], s1[MS];
    
    int main()
    {
        scanf("%s", s1); l = strlen(s1); 
        rep(i, 1, l) s[i-1] = s1[i-1]; s[l] = ' '; n = l+1;
        scanf("%s", s1); l = strlen(s1);
        rep(i, 1, l) s[n+i-1] = s1[i-1]; n += l;
        rep(i, 1, n) rk[i] = s[i-1];
        p = 1; while (p <= n)
        {
            rep(i, 1, n) q[i].x = rk[i], q[i].y = i+p>n ? 0 : rk[i+p], q[i].z = i; sort(q+1, q+1+n);
            a = 0; rep(i, 1, n) if (q[i].x != q[i-1].x || q[i].y != q[i-1].y) rk[q[i].z] = ++a; else rk[q[i].z] = a;
            if (a == n) break; else p *= 2;
        }
        rep(i, 1, n) sa[rk[i]] = i;
        a = 0; rep(i, 1, n)
        {
            if (a) a--; p = sa[rk[i]-1];
            while (s[p+a-1] == s[i+a-1]) a++; h[rk[i]] = a;
        }
        l = sa[1]; rep(i, 3, n) if ((sa[i-1] < l && sa[i] > l) || (sa[i-1] > l && sa[i] < l)) ans = max(ans, h[i]);
        printf("%d", ans);
        return 0;
    }
    View Code

    POJ 3415: Common Substrings

    从上到下遍历Height,分组讨论。对于每个组,答案加上组内来自不同串的后缀两两之间的公共前缀长度之和。这一步得用单调栈维护才能够比较快。。。

    #include <cstdio>
    #include <fstream>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 234567
    #define MAX 1073741823
    
    using namespace std;
    
    struct node
    {
        int x, y, z;
        bool operator < (const node &k) const { return x < k.x || (x == k.x && y < k.y); }
    } q[MS];
    int n, k, l, la, rk[MS], sa[MS], h[MS], a, p, b;
    long long ans, as, bs;
    char s[MS], s1[MS];
    int am, bm;
    struct node2 {int x, y;} ac[MS], bc[MS];
    
    int main()
    {
        scanf("%d", &k);
        while (k)
        {
            scanf("%s", s1); l = strlen(s1); rep(i, 1, l) s[i-1] = s1[i-1]; s[l] = ' '; n = la = l+1;
            scanf("%s", s1); l = strlen(s1); rep(i, 1, l) s[n+i-1] = s1[i-1]; n += l;
            rep(i, 1, n) rk[i] = s[i-1];
            p = 1; while (p <= n)
            {
                rep(i, 1, n) q[i].x = rk[i], q[i].y = i+p>n ? 0 : rk[i+p], q[i].z = i; sort(q+1, q+1+n);
                a = 0; rep(i, 1, n) if (q[i].x != q[i-1].x || q[i].y != q[i-1].y) rk[q[i].z] = ++a; else rk[q[i].z] = a;
                if (a == n) break; else p *= 2;
            }
            rep(i, 1, n) sa[rk[i]] = i;
            a = 0; rep(i, 1, n)
            {
                if (a) a--; p = sa[rk[i]-1];
                while (s[p+a-1] == s[i+a-1]) a++; h[rk[i]] = a; 
            } 
            ans = am = bm = h[1] = 0;
            rep(i, 1, n) h[i] += 1-k;
            rep(i, 1, n)
            {
                if (h[i] < 1) am = bm = as = bs = 0;
                a = am; while (a && ac[a].x > h[i]) 
                {
                    as -= (ac[a].x - h[i])*ac[a].y, ac[a].x = h[i]; if (a != am) ac[a].y += ac[a+1].y, am--;
                    a--;
                }
                b = bm; while (b && bc[b].x > h[i]) 
                {
                    bs -= (bc[b].x - h[i])*bc[b].y, bc[b].x = h[i]; if (b != bm) bc[b].y += bc[b+1].y, bm--;
                    b--;
                } 
                if (sa[i] > la) 
                    bc[++bm].x = MAX, bc[bm].y = 1, bs += MAX, ans += as;
                else
                    ac[++am].x = MAX, ac[am].y = 1, as += MAX, ans += bs;
            }
            printf("%lld
    ", ans); scanf("%d", &k);
        }
        return 0;
    }
    View Code

    SPOJ PHRASES: Relevant Phrases of Annihilation

    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #include <fstream>
    #include <cstdio>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 123456
    #define MAX 1073741823
    
    using namespace std;
    
    struct node
    {
        int x, y, z;
        bool operator < (const node &k) const { return x < k.x || (x == k.x && y < k.y); }
    } q[MS];
    int n, m, l, r, a, p, rk[MS], sa[MS], h[MS], b[MS], c[MS], d[MS];
    char s1[MS], s[MS];
    
    bool Query(int k)
    {
        a = p = 0;
        rep(i, 1, n) 
        {
            if (h[i] < k) a = 0, p++;
            if (b[sa[i]] && c[b[sa[i]]] != p) c[b[sa[i]]] = p, a++;
            if (a > m/2) return true;
        }
        return false;
    }
    
    int main()
    {
        scanf("%d", &m);
        while (m)
        {
            n = 0, r = MAX;
            rep(i, 1, m) 
            {
                scanf("%s", s1); l = strlen(s1); r = min(r, l);
                rep(j, 1, l) s[n+j-1] = s1[j-1], b[n+j] = i, d[n+j] = l-j+1; if (i<m) s[n+l] = ' ', n += l+1; else n += l;
            }
            rep(i, 1, n) rk[i] = s[i-1];
            p = 1; while (p <= n)
            {
                rep(i, 1, n) q[i].x = rk[i], q[i].y = i+p>n?0:rk[i+p], q[i].z = i;
                sort(q+1, q+1+n);
                a = 0; rep(i, 1, n) if (q[i].x != q[i-1].x || q[i].y != q[i-1].y) rk[q[i].z] = ++a; else rk[q[i].z] = a;
                if (a == n) break; else p *= 2;
            }
            rep(i, 1, n) sa[rk[i]] = i;
            a = 0; rep(i, 1, n)
            {
                if (a) a--; p = sa[rk[i]-1];
                while (s[p+a-1] == s[i+a-1]) a++; h[rk[i]] = a;
            } 
            h[1] = 0; rep(i, 2, n) if (min(d[sa[i-1]], d[sa[i]]) < h[i]) h[i] = min(d[sa[i-1]], d[sa[i]]);
            l = 0;
            while (l != r)
                if (Query((l+r)/2+1)) l = (l+r)/2+1; else r = (l+r)/2;
            if (!l) printf("?
    "); else
            {
                a = p = 0;
                rep(i, 1, n) 
                {
                    if (h[i] < l) a = 0, p++;
                    if (b[sa[i]] && c[b[sa[i]]] != p) c[b[sa[i]]] = p, a++;
                    if (a == m/2+1) { a = -MAX; rep(j, sa[i]-1, sa[i]+l-2) printf("%c", s[j]); printf("
    ");  }
                }
            }
            printf("
    "); scanf("%d", &m);
        }
        return 0;
    }
    View Code

    POJ 3294: Life Forms

    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #include <fstream>
    #include <cstdio>
    
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    #define MS 123456
    #define MAX 1073741823
    
    using namespace std;
    
    struct node
    {
        int x, y, z;
        bool operator < (const node &k) const { return x < k.x || (x == k.x && y < k.y); }
    } q[MS];
    int n, m, l, r, a, p, rk[MS], sa[MS], h[MS], b[MS], c[MS], d[MS];
    char s1[MS], s[MS];
    
    bool Query(int k)
    {
        a = p = 0;
        rep(i, 1, n) 
        {
            if (h[i] < k) a = 0, p++;
            if (b[sa[i]] && c[b[sa[i]]] != p) c[b[sa[i]]] = p, a++;
            if (a > m/2) return true;
        }
        return false;
    }
    
    int main()
    {
        scanf("%d", &m);
        while (m)
        {
            n = 0, r = MAX;
            rep(i, 1, m) 
            {
                scanf("%s", s1); l = strlen(s1); r = min(r, l);
                rep(j, 1, l) s[n+j-1] = s1[j-1], b[n+j] = i, d[n+j] = l-j+1; if (i<m) s[n+l] = ' ', n += l+1; else n += l;
            }
            rep(i, 1, n) rk[i] = s[i-1];
            p = 1; while (p <= n)
            {
                rep(i, 1, n) q[i].x = rk[i], q[i].y = i+p>n?0:rk[i+p], q[i].z = i;
                sort(q+1, q+1+n);
                a = 0; rep(i, 1, n) if (q[i].x != q[i-1].x || q[i].y != q[i-1].y) rk[q[i].z] = ++a; else rk[q[i].z] = a;
                if (a == n) break; else p *= 2;
            }
            rep(i, 1, n) sa[rk[i]] = i;
            a = 0; rep(i, 1, n)
            {
                if (a) a--; p = sa[rk[i]-1];
                while (s[p+a-1] == s[i+a-1]) a++; h[rk[i]] = a;
            } 
            h[1] = 0; rep(i, 2, n) if (min(d[sa[i-1]], d[sa[i]]) < h[i]) h[i] = min(d[sa[i-1]], d[sa[i]]);
            l = 0;
            while (l != r)
                if (Query((l+r)/2+1)) l = (l+r)/2+1; else r = (l+r)/2;
            if (!l) printf("?
    "); else
            {
                a = p = 0;
                rep(i, 1, n) 
                {
                    if (h[i] < l) a = 0, p++;
                    if (b[sa[i]] && c[b[sa[i]]] != p) c[b[sa[i]]] = p, a++;
                    if (a == m/2+1) { a = -MAX; rep(j, sa[i]-1, sa[i]+l-2) printf("%c", s[j]); printf("
    ");  }
                }
            }
            printf("
    "); scanf("%d", &m);
        }
        return 0;
    }
    View Code

    POJ 1226: Substrings

    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #include <fstream>
    
    #define MS 123456
    #define MAX 1<<30
    #define rep(i, l, r) for(int i = l; i <= r; i++)
    #define down(i, l, r) for(int i = l; i >= r; i--)
    
    using namespace std;
    
    struct node
    {
        int x, y, z;
        bool operator < (const node &k) const { return x < k.x || (x == k.x && y < k.y); }
    } q[MS];
    int n, T, m, a, p, l, r, rk[MS], sa[MS], h[MS], b[MS], d[MS], c[MS];
    char s1[MS], s[MS];
    
    bool Query(int k)
    {
        a = p = 0; rep(i, 1, m) c[i] = 0;
        rep(i, 1, n)
        {
            if (h[i] < k) a = 0, p++;
            if (b[sa[i]] && p != c[b[sa[i]]]) c[b[sa[i]]] = p, a++;
            if (a == m) return true;
        }
        return false;
    }
    
    int main()
    {
        scanf("%d", &T);
        while (T--)
        {
            scanf("%d", &m); n = 0, r = MAX;
            rep(i, 1, m)
            {
                scanf("%s", s1); l = strlen(s1); r = min(l, r);
                rep(j, 1, l) s[n+j-1] = s1[j-1], b[n+j] = i, d[n+j] = l-j+1; n += l+1; s[n-1] = ' ', b[n] = 0, d[n] = 0;
                rep(j, 1, l) s[n+j-1] = s1[l-j], b[n+j] = i, d[n+j] = l-j+1; n += l+1; s[n-1] = ' ', b[n] = 0, d[n] = 0;
            }
            n--; rep(i, 1, n) rk[i] = s[i-1];
            p = 1; while (p <= n)
            {
                rep(i, 1, n) q[i].x = rk[i], q[i].y = i+p>n?0:rk[i+p], q[i].z = i;
                sort(q+1, q+1+n);
                a = 0; rep(i, 1, n) if (q[i].x != q[i-1].x || q[i].y != q[i-1].y) rk[q[i].z] = ++a; else rk[q[i].z] = a;
                if (a == n) break; else p *= 2;
            }
            rep(i, 1, n) sa[rk[i]] = i;
            a = 0; rep(i, 1, n)
            {
                if (a) a--; p = sa[rk[i]-1];
                while (s[p+a-1] == s[i+a-1]) a++; h[rk[i]] = a;
            }
            h[1] = 0; rep(i, 2, n) if (min(d[sa[i-1]], d[sa[i]]) < h[i]) h[i] = min(d[sa[i-1]], d[sa[i]]);
            l = 0; while (l != r) if (Query((l+r)/2+1)) l = (l+r)/2+1; else r = (l+r)/2;
            printf("%d
    ", l);
        }
        return 0;
    }
    View Code

    上面三题都是二分答案+分组讨论,也没什么好说了。

     

    总计18道。。。

    累。。。

  • 相关阅读:
    数据结构——单链表(singly linked list)
    Java——判断回文
    C——swap
    Java动态数组
    mui框架下监听返回按钮
    Ubuntu 18.04版本下安装网易云音乐
    Linux安装Broadcom无线驱动
    EFI环境下的Ubuntu&Win10双系统安装
    Leaflet中添加的不同图层样式图标
    数据插入数据库时,提示表名不存在
  • 原文地址:https://www.cnblogs.com/NanoApe/p/4190320.html
Copyright © 2020-2023  润新知