• POJ1509 Glass Beads——SAM(后缀自动机)


    题面

      POJ1509

    解析

      题意就是求字符串的最小表示, 当然可以用O(n)的算法快速求出,码量也不大,但最近讲了SAM,要求我们用SAM做这道题, 那就用SAM做一波

      预处理还是一样,先要复制一遍原字符串,然后建立一个后缀自动机,从根节点开始,用贪心的思路优先选取最小的节点,然后向后跳,跳n步后就是答案, 这里一定可以跳n步,因为如果一开始是在后面区间内开始跳的话,假设这个点是n+p, 那在p点一定可以跳n步, 并且同时保证了字典序不变

      还有一个问题, 知道了序列,如何求出答案?当然不能O(n2)暴力求出, 这里有这个字符串的性质,如果我们的终止节点为q, 假如q点代表的right集合内只有一个点,那么q的len就是这个点的前缀长度,答案就是len-n+1; 如果q点代表的right集合内有不止1个点,容易知道这几个点的right一定在右半区间,并且以这个集合内的几个点为右端点的长度为n的字符串相同, 那么这个字符串存在循环节,这几个端点的前n个字符串相同,由于循环节的存在,最靠左的端点的前缀一定是其他端点的前缀的后缀,那么q点的len就是最靠左的端点的前缀的长度, 答案就是len-n+1。

    综上, 答案就是len[q] - n + 1

      代码:

    #include<cstdio>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int maxn = 10005 ;
    
    int T, n, las, cnt;
    char s[maxn];
    
    struct point{
        int ch[26], len, fa;
    }d[maxn<<2];
    
    void Add(int x)
    {
        int p = las, np = las = ++cnt;
        d[np].len = d[p].len + 1;
        for( ; p && !d[p].ch[x] ; p = d[p].fa)    d[p].ch[x] = np;
        if(!p)
            d[np].fa = 1;
        else
        {
            int q = d[p].ch[x];
            if(d[q].len == d[p].len + 1)
                d[np].fa = q;
            else
            {
                int nq = ++cnt;
                d[nq] = d[q];
                d[nq].len = d[p].len + 1;
                d[q].fa = d[np].fa = nq;
                for( ; p && d[p].ch[x] == q; p = d[p].fa)
                    d[p].ch[x] = nq;
            }
        }
    }
    
    void work()
    {
        int now = 1;
        for(int i = 1 ; i <= n; ++i)
            for(int j = 0; j < 26; ++j)
                if(d[now].ch[j])
                {
                    now = d[now].ch[j];
                    break;
                }
        printf("%d
    ", d[now].len - n + 1);
    }
    
    int main()
    {
        scanf("%d", &T);
        while(T--)
        {
            las = cnt = 1;
            memset(d,0,sizeof(d));
            scanf("%s", s+1);
            n = strlen(s+1);
            for(int i = 1; i <= n; ++i)
                Add(s[i]-'a');
            for(int i = 1; i <= n; ++i)
                Add(s[i]-'a');
            work();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    第六章:随机化(续1)
    第六章:随机化
    PAT甲组 1010 Radix (二分)
    关于我的2019年度总结
    Codeforces 567D:One-Dimensional Battle Ships(二分)
    Codeforces 567C:Geometric Progression(DP)
    Codeforces 567B:Berland National Library(模拟)
    HDU 4790:Just Random(容斥)
    Codeforces 450C:Jzzhu and Chocolate(贪心)
    Codeforces 450E:Jzzhu and Apples(构造,数学)
  • 原文地址:https://www.cnblogs.com/Joker-Yza/p/11197723.html
Copyright © 2020-2023  润新知