【LOJ #6071】「2017 山东一轮集训 Day5」字符串(Sam)

传送门

总感觉好像之前考试做过??

反正考虑从后往前填
如果每个点某个值没有出边
往后面第一个根出去存在这个值的连向的那个点连边跑拓扑排序即可
不用实在连,记一下即可

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?EOF:*ib++;
}
inline int read(){
    char ch=gc();
    int res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
inline void readstring(vector<char> &s){
	char ch=gc();
	while(isspace(ch))ch=gc();
	while(!isspace(ch)&&ch!=EOF)s.pb(ch),ch=gc();
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int mod=1e9+7;
inline int add(int a,int b){return (a+=b)>=mod?(a-mod):a;}
inline int mul(int a,int b){static ll r;r=1ll*a*b;return (r>=mod)?(r%mod):r;}
inline void Add(int &a,int b){(a+=b)>=mod?(a-=mod):0;}
inline void Mul(int &a,int b){static ll r;r=1ll*a*b;a=(r>=mod)?(r%mod):r;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
inline int fix(int x){return (x<0)?x+mod:x;}
cs int N=1000005;
int f[26];
namespace Sam{
	cs int N=::N<<1;
	int nxt[N][26],tot,last,fa[N],len[N],g[N];
	inline void init(){
		while(tot)memset(nxt[tot],0,sizeof(nxt[tot])),fa[tot]=len[tot]=g[tot]=0,tot--;
		last=tot=1;
	}
	inline void insert(int c){
		int cur=++tot,p=last;last=cur;
		len[cur]=len[p]+1;
		for(;p&&!nxt[p][c];p=fa[p])nxt[p][c]=cur;
		if(!p)fa[cur]=1;
		else{
			int q=nxt[p][c];
			if(len[p]==len[q]-1)fa[cur]=q;
			else{
				int clo=++tot;
				fa[clo]=fa[q],len[clo]=len[p]+1;
				memcpy(nxt[clo],nxt[q],sizeof(nxt[clo]));
				for(;p&&nxt[p][c]==q;p=fa[p])nxt[p][c]=clo;
				fa[q]=fa[cur]=clo;
			}
		}
	}
	int buc[N],rk[N];
	inline void solve(){
		for(int i=0;i<=tot;i++)buc[i]=0;
		for(int i=1;i<=tot;i++)buc[len[i]]++;
		for(int i=1;i<=tot;i++)buc[i]+=buc[i-1];
		for(int i=tot;i>=1;i--)rk[buc[len[i]]--]=i;
		for(int i=tot;i>=1;i--){
			int u=rk[i];g[u]=1;
			for(int c=0;c<26;c++){
				int v=nxt[u][c];
				if(v)Add(g[u],g[v]);
				else Add(g[u],f[c]);
			}
		}
		for(int i=0;i<26;i++)if(nxt[1][i])f[i]=g[nxt[1][i]];
	}
}
vector<char> s[N];
int n;
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	n=read();
	for(int i=1;i<=n;i++)readstring(s[i]);
	for(int i=n;i>=1;i--){
		Sam::init();
		for(int j=0;j<s[i].size();j++)Sam::insert(s[i][j]-'a');
		Sam::solve();
	}
	int res=0;
	for(int j=0;j<26;j++)Add(res,f[j]);
	cout<<add(res,1)<<'\n';
	return 0;
}
posted @ 2020-02-17 14:58  Stargazer_cykoi  阅读(249)  评论(0编辑  收藏  举报