问题描述
新年了,蒜厂 BOSS 要给小蒜头们发新年礼物,其中有一份神秘大奖,但却不知道应该发给谁。于是,蒜厂 BOSS 打算让大家玩一个游戏。
一共有 n 个字符串排成一排,蒜头需要从中按顺序选取一部分字符串,使得选出来的字符串顺序和原顺序一致(也就是从中选出一个子序列),且靠前的字符串 xi 和靠后的字符串 xj 之间均同时满足如下要求:
xi是 xj的前缀
xi 是 xj 的后缀
蒜头需要从中按顺序选取最多的字符串,并且满足如上的要求。蒜厂 BOSS 最后会给选出最多字符串的蒜头们平分神秘大奖。你能算出选取的最大个数么?
输入格式
第一行输入一个整数 N,紧接着输入 N 行字符串,每个字符串仅包含大写字母。
输入数据总共少于 2×1e6 个字符。
输出格式
输出一个整数,表示最大个数。
样例输入
5
A
ABA
BBB
ABABA
AAAAAB
样例输出
3
AC代码
#include<bits/stdc++.h>
#define maxn 1000005
#define maxm 28*2
using namespace std;
int *a[maxn],tot,cnt[maxn],n,z;
int dp[maxn],fail[maxn],len;
int *nex;
string s;
void change(){
len=s.length();
for(int i=0;i<len;i++){
int c=s[i];
if(c>='a'&&c<='z'){
c=c-'a'+'Z'+1;
}
s[i]=c;
}
}
void getfail(){
nex=NULL;
nex=new int [s.length()+5];
memset(nex,-1,sizeof(int)*(s.length()+5));
nex[0]=len;
int p=0;
while(p<len-1&&s[p]==s[p+1]) p++;
if(len==1) return;
nex[1]=p;
int k=1,l;
for(int i=2;i<len;i++){
p=k+nex[k];
l=nex[i-k];
if(i+l<=p) nex[i]=l;
else{
int j=p-i;
if(j<0) j=0;
while(i+j<len&&s[i+j]==s[j]) j++;
nex[i]=j;
k=i;
}
}
}
void zds(int q){
int p=0;
for(int i=0;i!=len;i++){
if(a[p]==NULL){
a[p]=new int[maxm];
memset(a[p],-1,sizeof(int)*maxm);
}
if(a[p][s[i]-'A']==-1){
a[p][s[i]-'A']=++tot;
}
p=a[p][s[i]-'A'];
if(cnt[p]){
if(nex[len-1-i]==i+1){
int z=dp[q];
dp[q]=max(dp[q],dp[cnt[p]]+1);
}
}
}
cnt[p]=q;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) dp[i]=1;
for(int i=1;i<=n;i++){
cin>>s;
change();
getfail();
zds(i);
}
int maxx=1;
for(int i=1;i<=n;i++) maxx=max(maxx,dp[i]);
cout<<maxx;
return 0;
}