字符串难题

这道题是我出的啦。。
一开始是给小朋友做得暴力题。。于是我改造了一下。。



题目描述:
给出n个字符串,求只出现在k个字符串中的子串最长有多长

输入描述
第一行两个整数n,k
接着下来n行,每行一个字符串,全部由小写字母组成

输出描述
一个数,表示有多长

样例输入
3 2
abckde
abcde
abc
样例输出
2

样例解释
答案为deabc虽然很长,但是出现在了三个子串中,所以不能当作答案

数据范围
2<= n<=1000
每个字符串的长度<=1000
数据随机出

题解

其实并不是什么难题。。

一开始的时候是作为后缀数组出的啦,本来是想二分答案的
然后乱搞。。
接着因为没人验题,于是到考试那天才发现不满足二分性。。于是就把数据都调弱了,二分变成for了。。
这个方法在这个数据期望30分吧。。

然后正解,我只想到了后缀自动机,你就建广义的。。
然后将right集合的求法稍微改一改就知道出现在多少个串里了
然后就可以线性出解了,感觉很优越啊,这个方法!!

#include<cstdio>  
#include<cstring>  
const int N=560*1005;  
struct qq{int son[26],pre,step,lalal;}s[N];  
int last,tot;  
int n,m;  
int vis[N],cnt;  
void ins (int x)  
{  
    int np=++tot,p=last;  
    s[np].step=s[p].step+1;  
    while (p!=0&&s[p].son[x]==0) s[p].son[x]=np,p=s[p].pre;  
    if (p==0) s[np].pre=1;  
    else
    {  
        int q=s[p].son[x];  
        if (s[q].step==s[p].step+1) s[np].pre=q;  
        else
        {  
            int nq=++tot;  
            s[nq]=s[q];  
            s[nq].step=s[p].step+1;  
            s[q].pre=s[np].pre=nq;  
            while (p!=0&&s[p].son[x]==q) s[p].son[x]=nq,p=s[p].pre;  
        }  
    }  
    last=np;  
}  
int mymax (int x,int y)
{
    return x>y?x:y;
}
int main()  
{  
    memset(vis,0,sizeof(vis));cnt=0;  
    tot=1;  
    scanf("%d%d",&n,&m);  
    for (int u=1;u<=n;u++)  
    {  
        cnt++;  
        int Last=tot+1;  
        last=1;  
        char ch=getchar();  
        while (ch<'a'||ch>'z') ch=getchar();  
        while (ch>='a'&&ch<='z') ins(ch-'a'),ch=getchar();  
        for (int i=Last+1;i<=tot;i++)  
        {  
            int x=i;  
            while (x!=0&&vis[x]!=cnt)   
                vis[x]=cnt,s[x].lalal++,x=s[x].pre;  
        }  
    }  
    int ans=0;
    for (int u=1;u<=tot;u++)
        if (s[u].lalal==m)
            ans=mymax(ans,s[u].step);
    printf("%d\n",ans);
    return 0;  
}  
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值