HDU 4763 - Theme Section(KMP)

题目大意:给你一个串(串长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代码:

StatusAccepted
Time62ms
Memory7616kB
Length1592
LangC++
Submitted2018-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;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值