mxqz SAM RE
查看原帖
mxqz SAM RE
83999
Demoe楼主2021/8/7 20:05

萌新新学 SAM

报错报了 SIGSEGV /kk

求调/kel

// wish to get better qwq

#include<bits/stdc++.h>
#define re register int
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define dec(x) fixed<<setprecision(x)

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

template<class T> inline void rd(T &x){
	int fl=1;x=0;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') fl=-fl;
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	x*=fl;
}
template<class T> inline void wr(T x){
	if(x<0) x=-x,putchar('-');
	if(x<10){putchar(x+'0');return ;}
	int tmp[30]={0},cnt=0;
	while(x) tmp[cnt++]=x%10,x/=10;
	for(re i=cnt-1;i>=0;--i) putchar(tmp[i]+'0');
}

// ---------- IO ---------- //

const int N=2e6+5;// 记得开字符串长度两倍大小qwq
string s,t;
int op,Tt,n,mx[N],mn[N];

struct Suffix_Automaton{
	int tot,lst,maxlen[N],minlen[N],link[N],to[N][26],siz[N],in[N],tp[N],cntlen[N],ss[N];ll cntd,cntsum;queue<int> q;
	Suffix_Automaton(){tot=lst=1;}
	inline void clear(){
		for(re i=1;i<=tot;++i){
			maxlen[i]=minlen[i]=link[i]=siz[i]=in[i]=tp[i]=cntlen[i]=ss[i]=0;
			for(re j=0;j<26;++j) to[i][j]=0;
		}
		tot=lst=1;cntd=cntsum=0;
	}
	inline void insert(int ch){
		re nw=++tot,p=lst;siz[nw]=1;maxlen[nw]=maxlen[lst]+1;
		while(p&&!to[p][ch]) to[p][ch]=nw,p=link[p];
		if(!p) link[nw]=1;
		else{
			int t=to[p][ch];
			if(maxlen[p]+1==maxlen[t]) link[nw]=t;
			else{
				int cp=++tot;maxlen[cp]=maxlen[p]+1;
				for(re i=0;i<26;++i) to[cp][i]=to[t][i];
				while(p&&to[p][ch]==t) to[p][ch]=cp,p=link[p];
				link[cp]=link[t];link[t]=link[nw]=cp;
			}
		}
		lst=nw;cntd+=maxlen[nw]-maxlen[link[nw]];cntsum=1ll*maxlen[nw]*(maxlen[nw]+1)/2-1ll*maxlen[link[nw]]*(maxlen[link[nw]]+1)/2;
	}
	inline bool check(char s[],int n){
		int nw=1,i=1;
		for(;s[i];nw=to[nw][s[i]-'a'],++i)
			if(!to[nw][s[i]-'a']) break;
		return i==n;
	}// 判断模式串是否在原串中出现 
	inline void topo(){
		for(re i=2;i<=tot;++i) ++in[link[i]];
		for(re i=1;i<=tot;++i) if(!in[i]) q.push(i);
		while(!q.empty()){
			int x=q.front();q.pop();
			siz[link[x]]+=siz[x];
			if(!(--in[link[x]])) q.push(link[x]);
		}
	}// 拓扑排 个人比较喜欢写的好看的版本( 
	inline void topo2(){
		for(re i=1;i<=tot;++i) ++cntlen[maxlen[i]];
		for(re i=1;i<=tot;++i) cntlen[i]+=cntlen[i-1];
		for(re i=1;i<=tot;++i) tp[cntlen[maxlen[i]]--]=i;
//		for(re i=tot;i>0;--i) siz[link[tp[i]]]+=siz[tp[i]];
//		for(re i=1;i<=tot;++i) ss[i]=op?siz[i]:siz[i]=1;siz[1]=ss[1]=0;
//		for(re i=tot;i>0;--i)
//			for(re j=0;j<26;++j) ss[tp[i]]+=ss[to[tp[i]][j]];
	}// 拓扑排 用处比较多的版本 事实上是按 maxlen 从小到大排 效果一样( 
	// 其中 op=0 时不同位置的相同子串算作一个 op=1 时不同位置的相同子串算作多个 
	inline ll count(){
		/*topo();return siz[1]-1;*/return cntd;
	}// 原串不同子串个数  
	inline ll count2(){
		return cntsum;
	}// 原串不同子串长度和 
	inline void kth(int x,int k){
		if(ss[1]<k){puts("-1");return ;}
		if(k<=siz[x]){puts("");return ;}k-=siz[x];
		for(re i=0;i<26;++i)
			if(to[x][i]){
				if(k>ss[to[x][i]]) k-=ss[to[x][i]];
				else{putchar('a'+i);kth(to[x][i],k);return ;}
			}
	}// 字典序第 k 小的子串 
	inline int count3(char s[],int n){
		topo();
		int nw=1,i=1;
		for(;s[i];nw=to[nw][s[i]-'a'],++i)
			if(!to[nw][s[i]-'a']) break;
		if(i<n) return 0;
		return siz[nw];
	}// 计算模式串出现次数 
	inline string LCS(string T){
		int nw=1,l=0,ans=0,pos=0;
		for(re i=0;i<T.size();++i){
			while(nw&&!to[nw][T[i]-'a']) nw=link[nw],l=maxlen[nw];
			if(!nw) nw=1,l=0;
			if(to[nw][T[i]-'a']) nw=to[nw][T[i]-'a'],++l;
			if(l>ans) ans=l,pos=i;mx[nw]=max(mx[nw],l);
		}
		topo2();
		for(re i=tot;i>0;--i) mx[link[tp[i]]]=max(mx[link[tp[i]]],min(mx[tp[i]],maxlen[link[tp[i]]]));
		for(re i=1;i<=tot;++i) mn[i]=min(mn[i],mx[i]),mx[i]=0;
		return T.substr(pos-ans+1,ans);
	}// 两个字符串的最长公共子串 其中 mx 和 mn 用来维护多字符串最长公共子串 
	inline void solve(){
		int ans=0;topo();
		for(re i=1;i<=tot;++i) if(siz[i]>1) ans=max(ans,siz[i]*maxlen[i]);
		wr(ans);puts("");
	}// 板子题的 solve 求所有出现次数不为 1 的子串的出现次数乘上该子串长度的最大值 
}SAM;

// ---------- Suffix Automaton ---------- //

int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	for(re i=1;i<N;++i) mn[i]=N;
	cin>>s;int ans=0;
	for(re i=0;i<s.size();++i) SAM.insert(s[i]-'a');
	while(cin>>t) SAM.LCS(t);
	for(re i=0;i<SAM.tot;++i) ans=max(ans,mn[i]);
	cout<<ans<<endl;
	return 0;
}

// ---------- Main ---------- //
2021/8/7 20:05
加载中...