[NOI Online 2021 Improved Group] Building Block Competition-Suffix Automata + Sub-sequence Automata

Synchronized at: https://www.luogu.com.cn/blog/OUYE2020/solution-p7469

answer

Consider the essentially different substrings in the string T at most n 2 n^2n2. Violent enumeration judgment is at leastO (n 3) O(n^3)O ( n3 ), usehash hashh a s h can be optimized toO (n 2) O(n^2)O ( n2 ). However, in order to ensure correctness, we do not usehash hashh a s h (Actually, I only used this thing once when doing string questions.

So in order to remove the duplication, the best way is to TTT string creates a suffix automaton, and traverses the entire suffix automaton by side to be like atrie trieT R & lt I E tree obtained as information of each sub-string. Due to the suffix automata up to2n 2n2 n points, each point will traverse no more thannnn times (in fact, more thannnn is much smaller), so the amortized complexity isO (n 2) O(n^2)O ( n2 ), wheren> 26 n> 26n>2 6 is strictly less thanO (n 2) O(n^2)O ( n2)

How to take TTSubstring andSS in TWhat about subsequence matching in S ? We greedily recordfi, c f_{i,c}fi,cNo. iiThe first occurrence of the charactercc after i charactersc position, putiii f i , c f_{i,c} fi,cConnect the edges between them, and
finally get one at most n ∗ 26 n*26n2 Trie trie with 6 sidest r i e tree. According to greedy thinking, this tree must recordSSInformation about all subsequences of S , thistrie triet r i e tree is calledSSS isa subsequence automaton.

Then we only need to traverse the two automata synchronously, and find the number of all coincident nodes is the answer. This complexity is the smaller value of the traversal times of the two automata, so the total complexity is less than O (n 2) O(n^2)O ( n2)

Code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#define ll long long
#define MAXN 3005
#define uns unsigned
#define INF 0x3f3f3f3f
using namespace std;
inline ll read(){
    
    
	ll x=0;bool f=1;char s=getchar();
	while((s<'0'||s>'9')&&s>0){
    
    if(s=='-')f^=1;s=getchar();}
	while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar();
	return f?x:-x;
}
struct SAM{
    
    
	int ch[26],len,fa;
	SAM(){
    
    memset(ch,0,sizeof(ch)),len=fa=0;}
}sam[MAXN<<1];
int las=1,tot=1;
inline void samadd(int c){
    
    
	int p=las,np=las=++tot;sam[np].len=sam[p].len+1;
	for(;p&&sam[p].ch[c]==0;p=sam[p].fa)sam[p].ch[c]=np;
	if(!p)sam[np].fa=1;
	else{
    
    int q=sam[p].ch[c];
		if(sam[q].len==sam[p].len+1)sam[np].fa=q;
		else{
    
    
			int nq=++tot;sam[nq]=sam[q],sam[nq].len=sam[p].len+1,sam[q].fa=sam[np].fa=nq;
			for(;p&&sam[p].ch[c]==q;p=sam[p].fa)sam[p].ch[c]=nq;
		}
	}
}
int n,ans;
char a[MAXN],b[MAXN];
int tr[MAXN][26];
inline void dfs(int x,int y){
    
    
	if(!x||!y)return;
	if(x>1)ans++;
	for(int i=0;i<26;i++)
		dfs(sam[x].ch[i],tr[y][i]);
}
signed main()
{
    
    
//	freopen("block.in","r",stdin);
//	freopen("block.out","w",stdout);
	n=read();
	scanf("%s\n%s",a+2,b+1);
	for(int i=n;i>0;i--){
    
    
		for(int j=0;j<26;j++)tr[i][j]=tr[i+1][j];
		tr[i][a[i+1]-'a']=i+1;
	}
	for(int i=1;i<=n;i++)samadd(b[i]-'a');
	dfs(1,1);
	printf("%d\n",ans);
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43960287/article/details/115268627