zoukankan      html  css  js  c++  java
  • Kuangbin 带你飞 KMP扩展KMP Manacher

    首先是几份模版

    KMP

    void kmp_pre(char x[],int m,int fail[])
    {
        int i,j;
        j = fail[0] = -1;
        i = 0;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    int kmp_count(char x[],int m,char y[],int n)
    {
        int i = 0,j = 0;
        int ans = 0;
        while (i < n)
        {
            while (j != -1 && y[i] != x[j]) j = fail[j];
            i++;j++;
            if (j >= m)
            {
                ans++;
                j = fail[j];
            }
        }
        return ans;
    }

    最小表示法 。资料http://blog.csdn.net/acm_cxlove/article/details/7909087

    HDU 3374 String problem

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 1000010;
    char str[MAXN];
    int fail[MAXN];
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i = 0,j;
        j = fail[0] = -1;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    int getval(char * str,int len,bool type)
    {
        int i = 0,j = 1,k = 0;
        while (i < len && j < len && k < len)
        {
            int val = str[(j + k) % len] - str[(i + k) % len];
            if (val == 0) k++;
            else
            {
                if (type)
                {
                    if (val > 0) j += k + 1;
                    else i += k + 1;
                }
                else
                {
                    if (val > 0) i += k + 1;
                    else j += k + 1;
                }
                k = 0;
                if (i == j) j++;
            }
        }
        return min(i,j);
    }
    
    int main()
    {
        while (scanf("%s",str) != EOF)
        {
            int len = strlen(str);
            kmp_pre(str,len,fail);
            int l = getval(str,len,true);
            int r = getval(str,len,false);
            int ret = len % (len - fail[len]) ? 1 : len / (len - fail[len]);
            printf("%d %d %d %d
    ",l + 1,ret,r + 1,ret);
        }
        return 0;
    }

    扩展KMP 学习资料http://wenku.baidu.com/link?url=oRb889beOwu3N4gZHJ0W3o91I78GpCqjIGdOmfPIp3WD5GxCHdc3njCXu0ocgDKTSNaBG_deOWszmrVFZMrbTiureG3otYc522XrJcqdbry

    模版1:

    HDU 3613 BestReward

    将一个串分成2段,如果一段不是回文串,那么权值为0,否则为按照对应法则的权值

    权值不是很难统计直接前缀和

    这里用扩展KMP来判断回文串,将原串反转得到T,那么由扩展KMP的定义,

    判断前半段串如果是回文串的时候,就是以原串为模式传,反串为回文串,判断EXTEND[i] + i == len

    后半段同理直接暴力

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 500010;
    const int INF = 0x3f3f3f3f;
    char S[MAXN],T[MAXN];
    int fail[MAXN];
    int ext1[MAXN],ext2[MAXN];
    int val[30];
    int sum[MAXN];
    
    void pre_ekmp(char x[],int m,int fail[])
    {
        fail[0] = m;
        int j = 0;
        while (j + 1 < m && x[j] == x[j + 1]) j++;
        fail[1] = j;
        int k = 1;
        for (int i = 2 ; i < m ; i++)
        {
            int p = fail[k] + k - 1;
            int L = fail[i - k];
            if (i + L < p + 1) fail[i] = L;
            else
            {
                j = max(0,p - i + 1);
                while (i + j < m && x[i + j] == x[j]) j++;
                fail[i] = j;
                k = i;
            }
        }
    }
    
    void ekmp(char x[],int m,char y[],int n,int fail[],int extend[])
    {
        pre_ekmp(x,m,fail);
        int j = 0;
        while (j < n && j < m && x[j] == y[j])j++;
        extend[0] = j;
        int k = 0;
        for (int i = 1 ; i < n ; i++)
        {
            int p = extend[k] + k - 1;
            int L = fail[i - k];
            if (i + L < p + 1) extend[i] = L;
            else
            {
                j = max(0,p - i + 1);
                while (i + j < n && j < m && y[i + j] == x[j]) j++;
                extend[i] = j;
                k = i;
            }
        }
    }
    
    int main()
    {
        int kase;
        scanf("%d",&kase);
        while (kase--)
        {
            for (int i = 0 ; i < 26 ; i++) scanf("%d",&val[i]);
            scanf("%s",S);
            memset(sum,0,sizeof(sum));
            int len = strlen(S);
            for (int i = 0 ; i < len ; i++)
                sum[i + 1] = sum[i] + val[S[i] - 'a'];
            for (int j = len - 1,i = 0 ; j >= 0 ;j--,i++)
                T[i] = S[j];
            T[len] = '';
           // printf("%s %s
    ",S,T);
            ekmp(S,len,T,len,fail,ext1);
            ekmp(T,len,S,len,fail,ext2);
           // for (int i = 0 ; i <= len ; i++) printf("%d ",ext1[i]); puts("");
            //for (int i = 0 ; i <= len ; i++) printf("%d ",ext2[i]); puts("");
            //for (int i = 0 ; i <= len ; i++) printf("%d ",sum[i]); puts("");
            int ret = 0;
            for (int i = 0 ; i < len ; i++)
            {
                if (i > 0 && ext1[i] + i == len)
                {
                    int pos = ext1[i];
                    int res = sum[pos];
                   // printf("%d %d
    ",i,res);
                    if (ext2[pos] + pos == len)
                    {
                        res += sum[len] - sum[pos];
                    }
                   // printf("%d %d
    ",i,res);
                    ret = max(res,ret);
                }
                else
                {
                    int pos = i + 1;
                    int res = 0;
                    if (ext2[pos] + pos == len)
                        res += sum[len] - sum[pos];
                    ret = max(ret,res);
                }
            }
            printf("%d
    ",ret);
        }
        return 0;
    }
    View Code

    模版2 拼接多串的扩展KMP

    POJ 3376 Finding Palindromes

    求串串之间的组合方案中,有多少个回文串。

    贴一下别人的题解

    题意:给你n个字符串m1、m2、m3...mn 求S = mimj(1=<i,j<=n)是回文串的数量

    思路:我们考虑第i个字符串和第j个字符串能构成组合回文串要满足的条件:

    1、i的长度小于j,那么i一定是j的反串的前缀,且j的反串剩下的后缀是回文串

    2、i的长度等于j,那么i等于j的反串

    3、i的长度大于j,那么j的反串一定是i的前缀,且i串剩下的后缀是回文串

    我们可以将这n个字符串插入trie,每个节点要维护两个值:value1. 到当前节点的字符串个数;value2. 当前节点后面的回文子串个数

    我们用每个字符串的反串去trie上查找,要构成回文串有以下情况:

    1、 此反串是其他串的前缀,那么组合回文串的数量就要加上value2

    2、此反串的前缀是某些字符串,且反串剩下的后缀是回文串,那么组合回文串的数量要加上value1

    3、2的特例:此反串的前缀是某些字符串,且反串剩下的后缀为空,同样要加上value1,这种情况可以和2一起处理

    关键:

    1、判断字符串的哪些后缀是回文串(用于更新value2),以及对应反串的哪些后缀是回文串(当面临第二种情况时,可直接判断后缀否为回文串)

    2、如何更新value1和value2(借助1的结果)

    很好的题目。反正我看着这份题解搞的

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 2000010;
    const int MAXD = 26;
    struct node
    {
        int num;
        int tot;
        node * nxt[MAXD];
    }src[MAXN];
    
    node * root;
    int st[MAXN],ed[MAXN];
    bool flag[2][MAXN];
    char S[MAXN],T[MAXN];
    int extend[MAXN];
    LL ret;
    int cas;
    int fail[MAXN];
    
    void pre_ekmp(char x[],int lft,int rht)
    {
        int j = 0;
        while (lft + 1 + j <= rht && x[lft + j] == x[lft + j + 1]) j++;
        fail[lft + 1] = j;
        int k = lft + 1;
        for (int i = lft + 2 ; i <= rht ; i++)
        {
            int p = fail[k] + k - 1;
            int L = fail[lft + i - k];
            if (L + i < p + 1) fail[i] = L;
            else
            {
                j = max(0,p - i + 1);
                while (i + j <= rht && x[lft + j] == x[i + j]) j++;
                fail[i] = j;
                k = i;
            }
        }
    }
    
    void ekmp(char S[],char T[],int lft,int rht,bool type)
    {
        pre_ekmp(T,lft,rht);
        int j = 0;
        while (j + lft <= rht && S[j + lft] == T[lft + j])j++;
        extend[lft] = j;
        int k = lft;
        for (int i = lft + 1;  i <= rht ; i++)
        {
            int p = extend[k] + k - 1;
            int L = fail[lft + i - k];
            if (L + i < p + 1) extend[i] = L;
            else
            {
                j = max(0,p - i + 1);
                while (i + j <= rht && S[i + j] == T[lft + j])j++;
                extend[i] = j;
                k = i;
            }
        }
        for (int i = lft ; i <= rht  ; i++)
        {
            if (extend[i] + i == rht + 1)
                flag[type][i] = true;
        }
    }
    
    void Insert(char str[],int lft,int rht)
    {
        node * u = root;
        for (int  i = lft ; i <= rht ; i++)
        {
            int ch = str[i] - 'a';
            u -> tot += flag[0][i];
            if (u -> nxt[ch] == NULL)
            {
                u -> nxt[ch] = &src[cas++];
            }
            u = u -> nxt[ch];
        }
        u -> num++;
    }
    
    void Find(char *str,int lft,int rht)
    {
        node * u = root;
        for (int i = lft ; i <= rht ; i++)
        {
            int ch = str[i] - 'a';
            u = u -> nxt[ch];
            if (u == NULL) break;
            if ((i < rht && flag[1][i + 1]) || i == rht)
                ret += u -> num;
        }
        if (u != NULL) ret += u -> tot;
    }
    
    int main()
    {
        int N;
        while (scanf("%d",&N) != EOF)
        {
            ret = 0;
            cas = 0;
            memset(src,0,sizeof(src));
            memset(flag,false,sizeof(flag));
            root = &src[cas++];
            int length = 0;
            for (int i = 0 ; i < N ; i++)
            {
                int d;
                scanf("%d%s",&d,S + length);
                for (int j = 0 ; j < d ; j++)
                    T[length + j] = S[length + d - 1 - j];
                st[i] = length;
                ed[i] = length + d - 1;
                ekmp(S,T,st[i],ed[i],false);
                ekmp(T,S,st[i],ed[i],true);
                Insert(S,st[i],ed[i]);
                length += d;
            }
            for (int i = 0 ; i < N ; i++)
                Find(T,st[i],ed[i]);
            printf("%I64d
    ",ret);
        }
        return 0;
    }
    View Code

    Manacher

    POJ 3974 Palindrome

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 1000010;
    char ma[MAXN * 2];
    int mp[MAXN * 2];
    
    void Manacher(char str[],int len)
    {
        int l = 0;
        ma[l++] = '$';
        ma[l++] = '#';
        for (int i = 0 ; i < len ; i++)
        {
            ma[l++] = str[i];
            ma[l++] = '#';
        }
        ma[l] = 0;
        int mx = 0,id = 0;
        for (int i = 0 ; i < l ; i++)
        {
            mp[i] = mx > i ? min(mp[2 * id - i],mx - i) : 1;
            while(ma[i + mp[i]] == ma[i - mp[i]])mp[i]++;
            if (i + mp[i] > mx)
            {
                mx = i + mp[i];
                id = i;
            }
        }
        int ret = 0;
        for (int i = 0 ; i < l ; i++)
            ret = max(ret,mp[i] - 1);
        printf("%d
    ",ret);
    }
    char str[MAXN];
    
    int main()
    {
        int kase = 1;
        while (scanf("%s",str) != EOF)
        {
            if (strcmp(str,"END") == 0) break;
            printf("Case %d: ",kase++);
            Manacher(str,strlen(str));
        }
        return 0;
    }
    View Code

    HDU 4513 吉哥系列故事――完美队形II

    要求回文串是山峰式的,中间大。带点要求的回文串,相应修改马拉车代码

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 100010;
    int ma[MAXN * 2];
    int mp[MAXN * 2];
    int src[MAXN],N;
    
    void manacher(int str[],int len)
    {
        int l = 0;
        ma[l++] = '$';
        ma[l++] = '#';
        for (int i = 0 ; i < len ; i++)
        {
            ma[l++] = str[i];
            ma[l++] = '#';
        }
        ma[l] = 0;
        int mx = 0,id = 0;
        for (int i = 0 ; i < l ; i++)
        {
            mp[i] = mx > i ? min(mp[2 * id - i],mx - i) : 1;
            while(ma[i + mp[i]] == ma[i - mp[i]] && ma[i - mp[i]] <= ma[i - mp[i] + 2])
                mp[i]++;
            if(i + mp[i] > mx)
            {
                mx = i + mp[i];
                id = i;
            }
        }
        //for (int i = 0 ; i < l ; i++) printf("%d ",ma[i]); puts("");
        //for (int i = 0 ; i < l ; i++) printf("%d ",mp[i]); puts("");
        int ret = 0;
        for (int i = 0 ; i < l ; i++) ret = max(ret,mp[i] - 1);
        printf("%d
    ",ret);
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d",&N);
            for (int i = 0 ; i < N ; i++) scanf("%d",&src[i]);
            manacher(src,N);
        }
        return 0;
    }
    View Code

    HDU 3294 girl's reseach

    这个题目设计到答案输出。注意添加字符#是对偶数回文串有影响的

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 200010;
    char ma[MAXN * 2];
    int mp[MAXN * 2];
    int idx[MAXN * 2];
    char str[MAXN];
    map<char,char>res;
    
    void Manacher(char str[],int len)
    {
        memset(idx,-1,sizeof(idx));
        int l = 0;
        ma[l++] = '$';
        ma[l++] = '#';
        for (int i = 0 ; i < len ; i++)
        {
            idx[l] = i;
            ma[l++] = str[i];
            idx[l] = i;
            ma[l++] = '#';
        }
        ma[l] = 0;
        int mx = 0,id = 0;
        for (int i = 0 ; i < l ; i++)
        {
            mp[i] = mx > i ? min(mp[2 * id - i],mx - i) : 1;
            while(ma[i + mp[i]] == ma[i - mp[i]])mp[i]++;
            if (i + mp[i] > mx)
            {
                mx = i + mp[i];
                id = i;
            }
        }
        int ret = 0,post;
        for (int i = 0 ; i < l ; i++)
        {
            if (str[i] != '#' && str[i] != '$' && mp[i] - 1 > ret)
            {
                ret = mp[i] - 1;
                post = i;
            }
        }
        if (ret == 1) puts("No solution!");
        else
        {
            if (ret % 2)
            {
                printf("%d %d
    ",idx[post] - (ret - 1) / 2,idx[post] + (ret - 1) / 2);
                for (int j = idx[post] - (ret - 1) / 2 ; j <= idx[post] + (ret - 1) / 2 ; j++)
                    printf("%c",str[j]);
                puts("");
            }
            else
            {
                printf("%d %d
    ",idx[post] - ret / 2 + 1,idx[post] + ret / 2);
                for (int j = idx[post] - ret / 2 + 1 ; j <= idx[post] + ret / 2; j++)
                    printf("%c",str[j]);
                puts("");
            }
        }
    }
    
    int main()
    {
        char op[5];
        while (scanf("%s%s",op,str) != EOF)
        {
            res.clear();
            int pos = op[0] - 'a';
            for (int i = 0 ,j = pos ; i < 26 ; i++,j = (j + 1) % 26)
                res[j + 'a'] = i + 'a';
            int len = strlen(str);
            for (int i = 0 ; i < len ; i++)
            {
                str[i] = res[str[i]];
            }
            Manacher(str,len);
        }
        return 0;
    }
    View Code

    HDU 1711 Number Sequence

    找到最早匹配的位置模版题

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 1000010;
    const int MAXD = 10010;
    int src[MAXN],tag[MAXD];
    int N,M;
    int fail[MAXD];
    
    void kmp_pre(int x[],int m,int fail[])
    {
        int i,j;
        j = fail[0] = -1;
        i = 0;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    int kmp_count(int x[],int m,int y[],int n)
    {
        int i,j;
        int ans = 0;
        i = j = 0;
        while (i < n)
        {
            while (j != -1 && y[i] != x[j]) j = fail[j];
            i++;j++;
            if (j >= m)
            {
                return i - m;
                ans++;
                j = fail[j];
            }
        }
        return -1;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d%d",&N,&M);
            for (int i = 0 ; i < N ; i++) scanf("%d",&src[i]);
            for (int i = 0 ; i < M ; i++) scanf("%d",&tag[i]);
            kmp_pre(tag,M,fail);
            int ret = kmp_count(tag,M,src,N);
            printf("%d
    ",ret == -1 ? -1 : ret + 1);
        }
        return 0;
    }
    View Code

    HDU 1686 Oulipo

    可重叠子串出现次数

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 1000010;
    const int MAXD = 10010;
    char src[MAXN],tag[MAXD];
    int fail[MAXN];
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i,j;
        j = fail[0] = -1;
        i = 0;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    int kmp_count(char x[],int m,char y[],int n)
    {
        int i = 0,j = 0;
        int ans = 0;
        while (i < n)
        {
            while (j != -1 && y[i] != x[j]) j = fail[j];
            i++;j++;
            if (j >= m)
            {
                ans++;
                j = fail[j];
            }
        }
        return ans;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%s%s",tag,src);
            int lenn = strlen(src);
            int lenm = strlen(tag);
            kmp_pre(tag,lenm,fail);
            int ret = kmp_count(tag,lenm,src,lenn);
            printf("%d
    ",ret);
        }
        return 0;
    }
    View Code

    HDU 2087 剪花布条

    不可重叠子串的次数。记录匹配位置扫一遍即可

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 10010;
    char src[MAXN],tag[MAXN];
    int fail[MAXN];
    int tot,pos[MAXN];
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i = 0,j;
        j = fail[0] = -1;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    void kmp_count(char x[],int m,char y[],int n)
    {
        int i = 0 , j = 0;
        int ans = 0;
        while (i < n)
        {
            while (j != -1 && y[i] != x[j]) j = fail[j];
            ++i;
            ++j;
            if (j >= m)
            {
                pos[tot++] = i - m;
                j = fail[j];
                ans++;
            }
        }
    }
    
    int main()
    {
        while (scanf("%s",src) != EOF)
        {
            if (src[0] == '#') break;
            scanf("%s",tag);
            int m = strlen(tag);
            kmp_pre(tag,m,fail);
            int n = strlen(src);
            tot = 0;
            kmp_count(tag,m,src,n);
            if (tot == 0)
            {
                puts("0");
                continue;
            }
            int ret = 1,pre = 0;
            for (int i = 1 ; i < tot ; i++)
            {
                if (pos[i] - pos[pre] >= m)
                {
                    ret++;
                    pre = i;
                }
            }
            printf("%d
    ",ret);
        }
        return 0;
    }
    View Code

    HDU 3746 Cyclic Nacklace

    最少添加多少个字符使得字符串存在循环节,循环次数要大于等于2

    循环接长度为len-fail[len]计算答案即可

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 100010;
    char src[MAXN];
    int fail[MAXN];
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i = 0,j;
        j = fail[0] = -1;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%s",src);
            int len = strlen(src);
            kmp_pre(src,len,fail);
            if (fail[len] != 0 && len % (len - fail[len]) == 0)
            {
                puts("0");
                continue;
            }
            else
            {
                printf("%d
    ",(len - fail[len]) - fail[len] % (len - fail[len]));
            }
        }
        return 0;
    }
    View Code

    HDU 1358 Period

    依然求循环节

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 1000010;
    char str[MAXN];
    int fail[MAXN];
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i = 0 ,j;
        j = fail[0] = -1;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    int main()
    {
        int kase = 1;
        int m;
        while (scanf("%d",&m) != EOF)
        {
            if (m == 0) break;
            printf("Test case #%d
    ",kase++);
            scanf("%s",str);
            kmp_pre(str,m,fail);
            for (int i = 2 ; i <= m ; i++)
            {
                if (i % (i - fail[i]) == 0)
                {
                    if (i / (i - fail[i]) > 1)
                        printf("%d %d
    ",i,i / (i - fail[i]));
                }
            }
            puts("");
        }
        return 0;
    }
    View Code

    hust 1010 The Minimum Length

    某个串A复制无数次后变成串B,从B中截取一段子串C,给出C求最短的A

    注意到串一定是循环的。不要想复杂了 ,就是说我求出来循环节。后边也一定是循环的。 不用考虑去判断他。

    所以直接求C的循环接即可

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 1000010;
    char str[MAXN];
    int fail[MAXN];
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i = 0,j;
        j = fail[0] = -1;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    int main()
    {
        while (scanf("%s",str) != EOF)
        {
            int len = strlen(str);
            kmp_pre(str,len,fail);
            printf("%d
    ",len - fail[len]);
        }
        return 0;
    }
    View Code

    POJ 2406 循环节

    POJ 2752 Seek the Name, Seek the Fame

    求所有是前缀同时也是后缀的字串

    由NEXT定义直接递推的找next值即可

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 400010;
    char str[MAXN];
    int fail[MAXN];
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i = 0,j;
        j = fail[0] = -1;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    int tot;
    int ret[MAXN];
    int main()
    {
        while (scanf("%s",str) != EOF)
        {
            int len = strlen(str);
            kmp_pre(str,len,fail);
            tot = 0;
            int cur = len;
            ret[tot++] = len;
            while (fail[cur] > 0)
            {
                ret[tot++] = fail[cur];
                cur = fail[cur];
            }
            sort(ret,ret + tot);
            for (int i = 0 ; i < tot ; i++)printf("%d ",ret[i]);puts("");
        }
        return 0;
    }
    View Code

    POJ 3080 Blue Jeans

    直接暴力

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 1000;
    char str[MAXN],src[MAXN];
    int fail[MAXN];
    struct node
    {
        char word[80];
        int length;
        friend bool operator < (const node &a,const node &b)
        {
            return a.length < b.length;
        }
    }res[MAXN];
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i,j;
        j = fail[0] = -1;
        i = 0;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    bool kmp_find(char x[],int m,char y[],int n)
    {
        int i,j;
        i = j = 0;
        while(i < n)
        {
            while (j != -1 && y[i] != x[j]) j = fail[j];
            i++;
            j++;
            if (j >= m) return true;
        }
        return false;
    }
    
    int main()
    {
        //freopen("sample.txt","r",stdin);
        int T;
        scanf("%d",&T);
        while (T--)
        {
            int N;
            scanf("%d",&N);
            for (int i = 0 ; i < N ; i++)
            {
                scanf("%s",res[i].word);
                res[i].length = strlen(res[i].word);
            }
            sort(res,res + N);
            char tmp[110],cmp[110];
            int ret = 0;
            for (int l = 0 ; l < res[0].length ; l++)
            {
                for (int r = l ; r < res[0].length ; r++)
                {
                    int leap = 0;
                    for (int i = l ; i <= r ; i++)
                        tmp[leap++] = res[0].word[i];
                    tmp[leap] = '';
                    bool flag = false;
                    kmp_pre(tmp,leap,fail);
                    for (int i = 1 ; i < N ; i++)
                    {
                        if (!kmp_find(tmp,leap,res[i].word,res[i].length))
                        {
                            flag = true;
                            break;
                        }
                    }
                    if (!flag)
                    {
                        if (r - l + 1 > ret)
                        {
                            ret = r - l + 1;
                            int step = 0;
                            for (int i = l ; i <= r ; i++)
                                cmp[step++] = res[0].word[i];
                            cmp[step] = '';
                        }
                        else if (r - l + 1 == ret)
                        {
                            if (strcmp(tmp,cmp) < 0) strcpy(cmp,tmp);
                        }
                    }
                }
            }
            if (ret < 3) printf("no significant commonalities
    ");  
            else
            {
                printf("%s
    ",cmp);
            }
        }
        return 0;
    }
    View Code

    HDU 2594 Simpsons’ Hidden Talents

    是A串前缀B串后缀的最长串

    拼串求NEXT注意坑点最长串小于等于min(|A|,|B|);

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 100010;
    char str[MAXN];
    int fail[MAXN];
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i = 0,j;
        j = fail[0] = -1;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    int main()
    {
        while (scanf("%s",str) != EOF)
        {
            int len = strlen(str);
            int res = len;
            scanf("%s",str + len);
            len = strlen(str);
            kmp_pre(str,len,fail);
            int tmp = len - res;
            if (fail[len] == 0)
            {
                puts("0");
                continue;
            }
            for (int i = 0 ; i < min(res,min(tmp,fail[len])) ; i++)
                printf("%c",str[i]);
            putchar(' ');
            printf("%d
    ",min(res,min(tmp,fail[len])));
        }
        return 0;
    }
    View Code

    hdu 3336 Count the string

    根据next数组递推

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 200010;
    const int MOD = 10007;
    char str[MAXN];
    int fail[MAXN],num[MAXN];
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i = 0,j;
        j = fail[0] = -1;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    int main()
    {
        int T,kase = 1;
        scanf("%d",&T);
        while (T--)
        {
            int N;
            scanf("%d",&N);
            scanf("%s",str);
            kmp_pre(str,N,fail);
            memset(num,0,sizeof(num));
            for (int i = 1 ; i <= N ; i++)
                num[fail[i]] = (num[fail[i]] + 1) % MOD;
            int sum = 0;
            for (int i = 1 ; i <= N ; i++)
            {
                if (num[i] == 0) sum = (sum + 1) % MOD;
                else sum = (sum + num[i] + 1) % MOD;
            }
            printf("%d
    ",sum);
        }
        return 0;
    }
    View Code

    HDU 4300 Clairewd’s message

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 100010;
    int fail[MAXN];
    char trans[30],str[MAXN];
    int pos[MAXN];
    char tag[MAXN];
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i = 0,j;
        j = fail[0] = -1;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    int kmp_count(char x[],int m,char y[])
    {
        int i = 0 , j = 0;
        int n = strlen(y);
        while (i < n)
        {
            while (j != -1 && y[i] != x[j]) j = fail[j];
            i++;
            j++;
            if (j >= m)
            {
                j = fail[j];
            }
        }
        return j;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%s",trans);
            scanf("%s",str);
            int len = strlen(str);
            for (int i = 0 ; i < 26 ; i++) pos[trans[i] - 'a'] = i;
            for (int i = 0 ; i < len ; i++) tag[i] = pos[str[i] - 'a'] + 'a';
            tag[len] = '';
            kmp_pre(tag,len,fail);
            int ret = kmp_count(tag,len,str + (len + 1) / 2);
            for (int i = 0 ; i < len - ret ; i++)
                printf("%c",str[i]);
            for (int i = 0 ; i < len - ret ; i++)
                printf("%c",tag[i]);
            puts("");;
        }
        return 0;
    }
    View Code

    HDU 1238 直接暴力

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 210;
    int pos,N;
    int fail[MAXN];
    char src[MAXN],tag[MAXN];
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i = 0,j;
        j = fail[0] = -1;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    bool kmp_count(char x[],int m,char y[],int n)
    {
        int i = 0 ,j = 0;
        kmp_pre(x,m,fail);
        while (i < n)
        {
            while (j != -1 && y[i] != x[j]) j = fail[j];
            i++;
            j++;
            if (j >= m) return true;
        }
        return false;
    }
    
    char input[MAXN][MAXN];
    int length[MAXN];
    
    bool can(char *str)
    {
        int leng = strlen(str);
        for (int i = 0 ; i < N ; i++)
        {
            if (i == pos) continue;
            if (!kmp_count(str,leng,input[i],length[i] * 2)) return false;
        }
        return true;
    }
    
    bool judge(int mid)
    {
        for (int i = 0 ; i + mid <= length[pos]; i++)
        {
            char tmp[MAXN];
            int cas = 0;
            for (int j = i ; j <= i + mid - 1 ; j++)
                tmp[cas++] = input[pos][j];
            tmp[cas] = '';
            if (can(tmp)) return true;
        }
        return false;
    }
    
    void dealinput()
    {
        scanf("%d",&N);
        pos = 0;
        for (int i = 0 ; i < N ; i++)
        {
            scanf("%s",input[i]);
            length[i] = strlen(input[i]);
            if (length[i] < length[pos])
                pos = i;
            for (int j = length[i] - 1 ,k = length[i]; j >= 0 ; j--,k++)
                input[i][k] = input[i][j];
            input[i][length[i] * 2] = '';
        }
       // for (int i = 0 ; i < N ; i++)
        //    printf("%s %d
    ",input[i],length[i]);
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            dealinput();
            int L = 0,R = 100;
            int ans = 0;
            while (L <= R)
            {
                int mid = (L + R) / 2;
                if (judge(mid))
                {
                    ans = mid;
                    L = mid + 1;
                }
                else R = mid - 1;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    HDU 2328 Corporate Identity

    后缀数组又来了一次

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 900100;
    const int INF = 0x3f3f3f3f;
    int sa[MAXN],r[MAXN];
    int t1[MAXN],t2[MAXN],c[MAXN];
    int Rank[MAXN],height[MAXN];
    
    void build_sa(int s[],int n,int m)
    {
        int i,j,p,*x = t1,*y = t2;
        for(i = 0 ; i < m ; i++) c[i] = 0;
        for(i = 0 ; i < n ; i++) c[x[i] = s[i]]++;
        for(i = 1 ; i < m ; i++) c[i] += c[i - 1];
        for(i = n - 1 ; i >= 0 ; i--) sa[--c[x[i]]] = i;
        for(j = 1 ; j <= n ; j <<= 1)
        {
            p=0;
            for(i = n - j ; i < n ; i++) y[p++] = i;
            for(i = 0 ; i < n ; i++) if(sa[i] >= j) y[p++] = sa[i] - j;
            for(i = 0 ; i < m ; i++) c[i] = 0;
            for(i = 0 ; i < n ; i++) c[x[y[i]]]++;
            for(i = 1 ; i < m ; i++) c[i]+=c[i-1];
            for(i = n - 1 ; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
            swap(x,y);
            p = 1;
            x[sa[0]] = 0;
            for(i = 1 ; i < n ; i++)
                x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j] ? p - 1 : p++;
            if(p >= n)break;
            m = p;
        }
    }
    
    void getHeight(int s[],int n)
    {
        int i,j,k = 0;
        for(i = 0;i <= n ; i++) Rank[sa[i]] = i;
        for(i = 0;i < n ; i++)
        {
            if(k)k--;
            j = sa[Rank[i] - 1];
            while(s[i + k] == s[j + k])k++;
            height[Rank[i]] = k;
        }
    }
    /*
    int mm[MAXN];
    int best[20][MAXN];
    void initRMQ(int n)
    {
        mm[0] = -1;
        for(int i = 1 ; i <= n ;i++)
            mm[i] = ((i & (i - 1)) == 0)?mm[i - 1] + 1:mm[i - 1];
        for(int i = 1 ; i <=n ; i++) best[0][i] = i;
        for(int i = 1 ; i <=mm[n] ; i++)
            for(int j = 1 ; j + (1 << i) - 1 <= n ; j++)
            {
                int a=best[i - 1][j];
                int b=best[i - 1][j + (1 << (i - 1))];
                if(height[a] < height[b]) best[i][j] = a;
                else best[i][j] = b;
            }
    }
    
    int askRMQ(int a,int b)
    {
        int t;
        t=mm[b - a + 1];
        b -= (1 << t) - 1;
        a = best[t][a];b = best[t][b];
        return height[a]<height[b] ? a : b;
    }
    int lcp(int a,int b)
    {
        a = Rank[a];b = Rank[b];
        if(a > b)swap(a,b);
        return height[askRMQ(a + 1,b)];
    }
    */
    
    int num;
    int N,cas;
    bool vis[4010];
    char str[210];
    int belong[MAXN];
    int ans[MAXN],tot;
    
    bool judge(int mid)
    {
        int step = 1;
        while (true)
        {
            while (step <= N && height[step] < mid) step++;
            if (step > N) break;
            memset(vis,false,sizeof(vis));
            while (step <= N && height[step] >= mid)
            {
                int lft = belong[sa[step - 1]];
                int rht = belong[sa[step]];
                vis[lft] = vis[rht] = true;
                step++;
            }
            bool flag = false;
            for (int i = 0 ; i < num ; i++)
            {
                if (!vis[i])
                {
                    flag = true;
                    break;
                }
            }
            if (!flag) return true;
        }
        return false;
    }
    
    int ret;
    void output(int length)
    {
        ret = INF;
        int step = 1;
        while (true)
        {
            while (step <= N && height[step] < length) step++;
            if (step > N) break;
            int Min = sa[step - 1];
            memset(vis,false,sizeof(vis));
            while (step <= N && height[step] >= length)
            {
                int lft = belong[sa[step - 1]];
                int rht = belong[sa[step]];
                vis[lft] = vis[rht] = true;
                step++;
            }
            bool flag = false;
            for (int i = 0 ; i < num ; i++)
            {
                if (!vis[i])
                {
                    flag = true;
                    break;
                }
            }
            if (!flag)
            {
                ret = Min;
                break;
            }
        }
        for (int i = 0,j = ret ; i < length ; i++,j++)
            printf("%c",r[j] - 4005);
        putchar('
    ');
    }
    
    int main()
    {
        while (scanf("%d",&num) != EOF)
        {
            if (num == 0) break;
            cas = 0;
            int step = 0;
            for (int i = 0 ; i < num ; i++)
            {
                scanf("%s",str);
                int len = strlen(str);
                for (int j = 0 ; j < len ; j++)
                {
                    belong[cas] = i;
                    r[cas++] = str[j] + 4005;
                }
                belong[cas] = -1;
                r[cas++] = step;
                step++;
            }
            cas--;
            N = cas;
    
            build_sa(r,N + 1,5000);
            getHeight(r,N);
           // for (int i = 0 ; i <= N ; i++) printf("%d ",r[i]); puts("");
            int ans = 0,L = 1,R = 256;
            while (L <= R)
            {
                int mid = (L + R) / 2;
                if (judge(mid))
                {
                    ans = mid;
                    L = mid + 1;
                }
                else R = mid -1;
            }
           // printf("%d
    ",ans);
            if (ans == 0) puts("IDENTITY LOST");
            else
            {
                output(ans);
            }
        }
        return 0;
    }
    View Code

    HDU 2609 How many最小表示法在统计

    FZU 1901 求所有满足s[i] == s[i + k](所有i)的所有k 依然求循环节

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 1000010;
    char str[MAXN];
    int fail[MAXN];
    int ans[MAXN],tot;
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i = 0,j;
        j = fail[0] = -1;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    int main()
    {
        int T,kase = 1;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%s",str);
            int len = strlen(str);
            tot = 0;
            ans[tot++] = len;
            kmp_pre(str,len,fail);
            int cur = len;
            while (fail[cur] > 0)
            {
                ans[tot++] = fail[cur];
                cur = fail[cur];
            }
            for (int i = 1 ; i < tot ; i++) ans[i] = len - ans[i];
            sort(ans,ans + tot);
            printf("Case #%d: %d
    ",kase++,tot);
            for (int i = 0 ; i < tot ; i++)
                printf("%d%c",ans[i], i == tot - 1 ? '
    ' : ' ');
        }
        return 0;
    }
    View Code

    HDU 4763 求同时出现在前缀后缀中间且不重叠的最长串

    直接利用KMP暴力2次

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 1000010;
    char str[MAXN];
    int fail[MAXN];
    
    void kmp_pre(char x[],int m,int fail[])
    {
        int i = 0,j;
        j = fail[0] = -1;
        while (i < m)
        {
            while (j != -1 && x[i] != x[j]) j = fail[j];
            fail[++i] = ++j;
        }
    }
    
    bool flag[MAXN];
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%s",str);
            int len = strlen(str);
            kmp_pre(str,len,fail);
            memset(flag,false,sizeof(flag));
            int cur = len;
            while (cur > 0)
            {
                if(cur * 2 <= len) flag[cur] = true;
                cur = fail[cur];
            }
            int ans = 0;
            for (int i = len - 1 ; i > 1 ; i--)
            {
                cur = i;
                while (cur > 0)
                {
                    if (flag[cur] && i >= 2 * cur && cur + i <= len)
                    {
                        ans = max(ans,cur);
                        break;
                    }
                    cur = fail[cur];
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
     
  • 相关阅读:
    no space left on device
    功能测试用例
    数据库命令
    移动APP测试用例设计实践经验(转载)
    15个常用sql命令
    将Windows文件夹挂载到Linux上
    英语学习方法
    三种特质 做领导
    扬州之行 第一天
    list、dict、str虽然是Iterable,却不是Iterator
  • 原文地址:https://www.cnblogs.com/Commence/p/5063753.html
Copyright © 2011-2022 走看看