HDU 5510(ACM 2015 沈阳)Bazinga [KMP]

题意:给出N个串,标号从上到下为1..N,问最大标号的一个串,满足前N-1个串不全是其子串。

范围:T50组,N 500,串Len 2000

解法:首先发现 N*N*Len的复杂度是比较难卡过的,应该需要优化,优化的方向应该是N*Len,简单推理后发现,只需要一个指针指向要匹配的串,一旦匹配成功并且指针在当前匹配串的上方,指针下移++,否则指针停止即可(如果最后指针没指着匹配串,更新答案),然后对于每一个新串,都从上次指针停止的地方继续匹配,一开始当前欲匹配串为第2个,指针指着第一个,这样可以保证至多匹配N次,证明如下:

首先复杂度应该都会算,就是为什么这样可以保证答案正确的原因,首先指针能下移,必然是某个在指针下方的串包含了前面的串,那么前面的当然不需要再匹配了,只需要看看下面那个串是否会被包含就好了,然后就会很高兴的发现只要做N次Kmp就好了。


代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<iostream>
#include<stdlib.h>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<bitset>
#pragma comment(linker, "/STACK:1024000000,1024000000")
template <class T>
bool scanff(T &ret){ //Faster Input
    char c; int sgn; T bit=0.1;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    if(c==' '||c=='\n'){ ret*=sgn; return 1; }
    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
    ret*=sgn;
    return 1;
}
#define inf 1073741823
#define llinf 4611686018427387903LL
#define PI acos(-1.0)
#define lth (th<<1)
#define rth (th<<1|1)
#define rep(i,a,b) for(int i=int(a);i<=int(b);i++)
#define drep(i,a,b) for(int i=int(a);i>=int(b);i--)
#define gson(i,root) for(int i=ptx[root];~i;i=ed[i].next)
#define tdata int testnum;scanff(testnum);for(int cas=1;cas<=testnum;cas++)
#define mem(x,val) memset(x,val,sizeof(x))
#define mkp(a,b) make_pair(a,b)
#define findx(x) lower_bound(b+1,b+1+bn,x)-b
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int nexxt[2222];
int pd(char *s1,char *s2){
    memset(nexxt,-1,sizeof(nexxt)); //初始化为-1
    int n=strlen(s1);
    int m=strlen(s2);
    int i,j=-1;
    for(i=1;i<m;i++){
        while(j>=0&&s2[j+1]!=s2[i])j=nexxt[j];
        if(s2[j+1]==s2[i])j++;
        nexxt[i]=j;
    }
    j=-1;
    for(i=-1;i<n-1;i++){
        while(j>=0&&s2[j+1]!=s1[i+1])j=nexxt[j];
        if(s2[j+1]==s1[i+1])j++;
        if(j==m-1){
            return 1;
        }
    }
    return 0;

}
char s[555][2222];
int main(){
    tdata{
        int n;
        scanff(n);
        rep(i,1,n)scanf("%s",s[i]);
        int j=1;
        int ans=1;
        rep(i,2,n){
            while(j<i&&pd(s[i],s[j]))j++;
            if(i!=j)ans=i;
        }
        printf("Case #%d: ",cas);
        if(ans==1)printf("-1\n");
        else printf("%d\n",ans);

    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值