inlineintread(){ int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; }
constint N = 100010;
structSuffix_Automaton{ int fa[N<<1], trans[N<<1][26], len[N<<1], Last, Index; int v[N], sa[N<<1], mn[N<<1], h[N<<1]; char s[N];
voidextend(int c){ int P = Last,NP = ++Index; len[NP] = len[P] + 1; for (; P&&!trans[P][c]; P=fa[P]) trans[P][c] = NP; if (!P) fa[NP] = 1; //- else { int Q = trans[P][c]; if (len[P] + 1 == len[Q]) fa[NP] = Q; else { int NQ = ++Index; fa[NQ] = fa[Q]; len[NQ] = len[P] + 1; memcpy(trans[NQ], trans[Q], sizeof trans[Q]); fa[Q] = NQ; fa[NP] = NQ; for (; P&&trans[P][c]==Q; P=fa[P]) trans[P][c] = NQ; } } Last = NP; } voidbuild(){ Last = Index = 1; scanf("%s",s+1); int n = strlen(s+1); for (int i=1; i<=n; ++i) extend(s[i] - 'a'); // index和第一个串s1的下标大致是对应的,但是中间还有克隆的节点 for (int i=1; i<=Index; ++i) v[len[i]] ++; // 确实是只有n种长度..前缀的后缀-->所有的串-->所以只用n // 这里求前缀和只是为了下面能够求出排名数组,让他们按照深度占比权值(有点像权值线段树的那种) for (int i=1; i<=n; ++i) v[i] += v[i-1]; // sa[i] 排名为i的节点。按深度排名(拓扑用) // i号节点按照它的len在v中前缀和减减--->其实就是排名,按照节点的长度(也就是深度)--->因为越深越长 for (int i=1; i<=Index; ++i) sa[ v[len[i]]-- ] = i; } voidcalcc(){ int n = strlen(s+1), now = 0, p = 1; memset(h, 0, sizeof(h)); for (int i=1; i<=n; ++i) { int c = s[i] - 'a'; if (trans[p][c]) p = trans[p][c], now ++; else { for (; p&&!trans[p][c]; p=fa[p]); if (!p) now = 0, p = 1; else now = len[p] + 1, p = trans[p][c]; } h[p] = max(h[p], now); } // 拓扑倒序,parent树中从深度深的到浅的 for (int i=Index; i>=1; --i) { int t = sa[i]; mn[t] = min(mn[t], h[t]); // t节点有匹配,并且它的父节点(后缀link)不为源点--->那么让它的父节点的匹配值等于父节点的长度 // 因为前面的操作是对最长的适配,所以没有管较短串的匹配,所以这里管一下 // 但是为什么只对父节点,而不对更爷爷节点什么的呢,因为这个拓扑排序从底部向上,所以父节点在之后会出现 // 所以爷爷节点由后面出现的父节点去管理就行了 ====》 太精妙了,amazing! if (h[t] && fa[t]) h[fa[t]] = len[fa[t]]; } } voidsolve(){ build(); memset(mn, 0x3f, sizeof(mn)); while (scanf("%s",s+1) != EOF) calcc(); int ans = 0; for (int i=1; i<=Index; ++i) ans = max(ans, mn[i]); printf("%d",ans); } }sam;
inlineintread(){ int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; }
constint N = 200010;
structSuffixAutomaton{ int Last, Index, res, cur, fa[N], trans[N][26], len[N]; SuffixAutomaton() {Last = Index = cur = 1; res = 0;} voidextend(int c){ int P = Last, NP = ++Index; len[NP] = len[P] + 1; for (; P&&!trans[P][c]; P=fa[P]) trans[P][c] = NP; if (!P) fa[NP] = 1; else { int Q = trans[P][c]; if (len[P] + 1 == len[Q]) fa[NP] = Q; else { int NQ = ++Index; fa[NQ] = fa[Q]; len[NQ] = len[P] + 1; memcpy(trans[NQ], trans[Q], sizeof trans[Q]); fa[Q] = NQ; fa[NP] = NQ; for (; P&&trans[P][c]==Q; P=fa[P]) trans[P][c] = NQ; } } Last = NP; } intsolve(int c){ if (trans[cur][c]) {cur = trans[cur][c]; res++; return res;} for (; cur&&!trans[cur][c]; cur=fa[cur]); if (!cur) res = 0, cur = 1; else res = len[cur] + 1, cur = trans[cur][c]; return res; } }sam[9];
char s[N]; char str[N>>1];
intmain(){ int n = 0,t = 0,len; scanf("%s",str+1);
while (scanf("%s",s+1)!=EOF) { len = strlen(s + 1); for (int i=1; i<=len; ++i) sam[t].extend(s[i] - 'a'); t ++; } int ans = 0; len = strlen(str+1); for (int i=1; i<=len; ++i) { int tmp = 1e9; for (int j=0; j<t; ++j) tmp = min(tmp, sam[j].solve(str[i] - 'a')); ans = max(ans, tmp); } printf("%d",ans); return0; }