题目大意:给你一个串(串长1e6),输出该串在前缀、后缀出现过,且在中间出现过至少一次的串的最大长度的值。
题目思路:最长的可能就是r=next[m](m为该串的长度),先判断一下是否可行,可行直接输出。
否则记l=0,mid=(l+r)/2,mid为答案串的长度,二分查找长度。
mid可行就用l保存下来,不可行就用r保存下来,这样最后的l就是答案。
从[mid,m-mid-1]中找是否存在[0,mid-1]长的子串,找到一个即可。
时间复杂度:O(nlogn)
AC代码:
Status | Accepted |
---|---|
Time | 62ms |
Memory | 7616kB |
Length | 1592 |
Lang | C++ |
Submitted | 2018-09-05 18:07:40 |
Shared |
Select Code
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <bitset>
const int INF=0x3f3f3f3f;
const int mod=10007;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int>
#define si set<int>
#define pii pair<int,int>
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int net[1000005];
char t[1000005],w[1000005];
void init()
{
mem(t,0);
mem(net,0);
}
int kmppre(char x[])
{
int m=strlen(x);
int i=0,j=net[0]=-1;
while(i<m)
{
while(j!=-1&&x[i]!=x[j])
{
j=net[j];
}
net[++i]=++j;
}
return net[m];
}
void cpy(char x[],char y[],int r)
{
strcpy(x,y);
x[r]='\0';
}
bool KMPcount(char x[],char y[],int lpos,int rpos)
{
int m=strlen(x),n=strlen(y);
int j=0;
while(lpos<n&&lpos<=rpos)
{
while(j!=-1&&y[lpos]!=x[j])j=net[j];
lpos++,j++;
if(j>=m)return 1;
}
return 0;
}
int main()
{
int T;
sci(T);
while(T--)
{
init();
scanf("%s",t);
int len=strlen(t),l=0,r=kmppre(t);
//printf("::%d\n",r);
for(int i=0;r-l>=1&&i<=20;++i)
{
int mid=(!i)?r:(l+r)/2;//第一次先判右端界
cpy(w,t,mid);
if(KMPcount(w,t,mid,len-mid-1))l=mid;
else r=mid;
}
printf("%d\n",l);
}
return 0;
}