hdu 5510 Bazinga KMP+尺取法

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5510

题意:至多50组数据,每组数据至多500个字符串,每个字符串的长度最长为2000.问最大的下标(从1开始)j,使得存在i < j使得s[i]不是s[j]的子串;

思路:KMP很容易想到,因为Trie是处理前缀串的,不能处理子串。在KMP中,还要优化下,就是父串可以代表子串,并且直接递推处理(用尺取法,每次处理没有父串的串)即可;

#include<bits/stdc++.h>
using namespace std;
#define rep0(i,l,r) for(int i = (l);i < (r);i++)
#define rep1(i,l,r) for(int i = (l);i <= (r);i++)
#define rep_0(i,r,l) for(int i = (r);i > (l);i--)
#define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
#define MS0(a) memset(a,0,sizeof(a))
#define MS1(a) memset(a,-1,sizeof(a))
#define MSi(a) memset(a,0x3f,sizeof(a))
#define inf 0x3f3f3f3f
#define lson l, m, rt << 1
#define rson m+1, r, rt << 1|1
typedef pair<int,int> PII;
#define A first
#define B second
#define MK make_pair
typedef __int64 ll;
typedef unsigned int uint;
template<typename T>
void read1(T &m)
{
    T x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    m = x*f;
}
template<typename T>
void read2(T &a,T &b){read1(a);read1(b);}
template<typename T>
void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);}
template<typename T>
void out(T a)
{
    if(a>9) out(a/10);
    putchar(a%10+'0');
}
int T,kase = 1,i,j,k,n,m,ans;
char s[505][2020];
int f[2020];
void getfail(char *p)
{
    f[0] = f[1] = 0;
    int n = strlen(p);
    for(int i = 1;i < n;i++){
        int j = f[i];
        while(j && p[i] != p[j]) j = f[j];//之前写的KMP竟然写成了if()..竟然过了
        f[i+1] = (p[i] == p[j] ?j+1:0);// i+1会递推到第n位
    }
}
bool Find(char *p,char *T)
{
    getfail(p);
    int j = 0,n = strlen(T),m = strlen(p);
    for(int i = 0;i < n;i++){
        while(j && T[i] != p[j]) j = f[j];
        if(T[i] == p[j]) j++;
        if(j == m) return true;
    }
    return false;
}
int main()
{
    //freopen("data.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    read1(T);
    while(T--){
        MS0(Next);
        read1(n);
        rep1(i,1,n) scanf("%s",s[i]);
        int ans = -1;
        for(int l = 1,r = 2;r <= n;r++){
            while(l < r){  //用尺取法之后就不需要再进行前驱表示父子关系了
                if(Find(s[l],s[r])) l++;
                else{ ans = r;break;}
            }
        }
        printf("Case #%d: %d
",kase++,ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/hxer/p/5345402.html