MLE 求调
查看原帖
MLE 求调
916028
thlog5楼主2025/7/25 11:05

记录

#include<bits/stdc++.h>
using namespace std;
#define il inline
typedef long long LL;
typedef unsigned long long ULL;
//#define int LL

namespace FastRead{
	struct InRead{
		template<typename T> T read(){
			T x=0;int f=1,ch=getchar();
			while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
			while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
			return x*f;
		}
//		template<typename T> void read(T &x){x=read<T>();}
		template<typename T> InRead& operator>>(T &x){return x=read<T>(),(*this);}
	}in;
	struct OutPut{
		template<typename T> void write(T x){
			if(x<0)x=-x,putchar('-');
			if(x>9)write(x/10);
			putchar(x%10+48);
		}
		template<typename T> OutPut& write(T x,int c){return write(x),putchar(c),(*this);}
		template<typename T> OutPut& operator<<(T x){return write(x),(*this);}
	}out;
}using namespace FastRead;

typedef const int& ci;
#define For(i,t,n) for(int i=t;i<=n;++i)
#define For_(i,t,n) for(int i=t;i>=n;--i)
const int inf=0x3f3f3f3f;
const int MAXN=155;

    int ch[MAXN][30]; //树边、转移边终点
    int id[MAXN],idx=0;
    int nxt[MAXN]; //回跳边终点
struct node{
    int time,id;
}ans[MAXN];
il bool cmp(const node&a,const node&b){
    if(a.time==b.time) return a.id<b.id;
    return a.time>b.time;
}

void clear(ci p){
    For(i,0,25)ch[p][i]=0;
    id[p]=nxt[p]=0;
}

    //1.构造trie树
    void insert(char *s,int idd){ //trie,根节点(0)表示空串,是模式串则打标记
        int p=0;          //每个节点表示根到该节点的字符串
        for(int i=0;s[i];++i){
            int j=s[i]-'a';
            if(!ch[p][j]) ch[p][j]=++idx,clear(ch[p][j]);
            p=ch[p][j];
        }
        id[p]=ans[idd].id=idd;
    }
    //2.构造AC自动机 在trie上构建 回跳边 和 转移边
    void build(){ //bfs构建AC自动机
        queue<int> q;
        For(i,0,25) if(ch[0][i]) q.push(ch[0][i]);
        while(q.size()){
            int u=q.front(); q.pop();
            For(i,0,25){
                int v=ch[u][i]; 
                if(v) nxt[v]=ch[nxt[u]][i],q.push(v); 
                //子节点存在,建立子节点回跳边并入队
                else ch[u][i]=ch[nxt[u]][i];
                //不存在,自建转移边
            }
        }
    }
    //3.查找单词出现次数
    //扫描主串,依次取出字符 s[k].
    //(1)i指针走主串对应的节点,沿着树边或转移边走,保证不回退。
    //(2)j指针沿着回跳边搜索模式串,每次从当前节点走到根节点,把当前节点中的所有后缀模式串一网打尽,保证不漏解。
    //(3)扫描完主串,返回答案。
    //算法一边走串,一边把当前串的所有后缀串搜出来,实在是强。
    int query(char *s){
        int ans111=0;
        for(int k=0,i=0;s[k];++k){
            int v=s[k]-'a';
            i=ch[i][v];
            for(int j=i;j;j=nxt[j]){
                ans[id[j]].time++;
            }
        }
        return ans111;
    }


int n;
char s[MAXN][75];
char t[1000005];

void solve(){
    in>>n; if(!n)exit(0);
    clear(0); idx=0;
    For(i,1,n){
        scanf("%s",s[i]);
        insert(s[i],i);
    }
    build();
    scanf("%s",t);
    query(t);
    sort(ans+1,ans+n+1,cmp);
    printf("%d\n",ans[1].time);
    For(i,1,n){
        if(ans[i].time<ans[1].time) break;
        printf("%s\n",s[ans[i].id]);
    }
    For(i,1,n) ans[i].time=ans[i].id=0;
}

signed main(){
	while(1)solve();
	return 0;
}
2025/7/25 11:05
加载中...