计蒜客习题:新年礼物


问题描述

新年了,蒜厂 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;
} 

猜你喜欢

转载自blog.csdn.net/liukairui/article/details/80627311