字符串难题

来源:互联网 发布:seo实战密码电子书 编辑:程序博客网 时间:2024/05/21 05:20

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

题目描述:给出n个字符串,求只出现在k个字符串中的子串最长有多长输入描述第一行两个整数n,k接着下来n行,每行一个字符串,全部由小写字母组成输出描述一个数,表示有多长样例输入3 2abckdeabcdeabc样例输出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;  }  
原创粉丝点击