题解 P1470 【最长前缀 Longest Prefix】

 首先看题,题目要求我们求最长匹配的长度,我们不妨如下思考:

​ 对于字符串S,我们从第y位开始搜索(保证前y-1位一定可以是匹配)

​ 从第y位开始生成字符串,若此时生成的字符串在P中出现过,则证明

​ 此时的字符串可以被匹配到y+i的位置,我们再从y+i+1开始搜索便好了!

​ 而问题的答案就是我们已到达的最大的一个y。

        那么问题来了,如果按照上述说法搜索,复杂度不稳定,但一定会

​ 超时的,有木有什么优化呢?

        答案是有的(不然我写这个题解干什么呢?),我们注意到,如果

​ 对于此时的y,我们曾经到达过,虽然到达的方式不同,但我们到达过,后

​ 面我们进行搜索的过程与结果肯定是一样的,所以,我们就跳过就好啦!

​ 而总的复杂度最高位O(n)(n为S串的长度),一下便是完整代码(加了点小优

​ 化):

#include<bits/stdc++.h>
using namespace std;
map<string,bool>s;//一个map解千愁~就是<u>**速度慢了点**</u>,大佬请自行打**hash**
int x;
int ans=0;
int ams=0;
string l;
bool F=0;
bool come[200001];
inline void to_search(int now){ 
    if(come[now]){//如果曾经搜索过此时的‘y’
        return;//退出
    }
    come[now]=1;//标记搜索过此时的‘y’
    if(now==x){
        return;
    }
    string qu="";
    for(int i=now;i<x;++i){
        if(i-now>=ams){//如果现在加的元素大于了最长元素,之后一定不可能成立,于是跳过(虽然是小优化,也很强大有不有~)
            return;
        }
        qu+=l[i];
        if(s[qu]){//如果P集合中有此时的元素
            F=1;//判断成立
            if(i>ans){//记录答案
                ans=i;
            }
            to_search(i+1);//从下一个y开始搜索
        }
    }
}
int main(){
    int e=1;
    while(cin>>l){
        if(l=="."){
            break;
        }
        s[l]=1;//标记元素存在
        if(l.size()>ams){
            ams=l.size();//记录最长元素(小优化第一步)
        } 
    }
    string yu="";
    while(cin>>l){//输入字符串S
        yu+=l;//将字符串S整合
    }
    l=yu;
    x=l.size();//得到S的长度
    to_search(0);//从第一个字符开始搜索
    if(!F){//注意判断是否搜索过,第一个点的坑QWQ
        printf("0");
        return 0;
    }
    printf("%d",ans+1);//输出答案(记得加一,因为是从0开始搜的)
    return 0;
}
原文地址:https://www.cnblogs.com/ThinkofBlank/p/10146136.html