[Zhengrui 2021 winter vacation provincial election second round of training day 1] string (suffix automata + memory)

description

The substring that defines a string is a string composed of characters in a continuous range of the string. For example, the substrings of "djq" are "d", "j", "q", "dj", "jq", and "djq".

Define F(a,b) as the longest substring of string a that appears at least once in string bb, for example:
F("dmqdjx","jdmqdx") = 4 Given n strings s0, s1, …, sn−1 and q groups of queries (xj, yj)
For each group of queries, you need to ask for F(sxj, syj).

Input format The
first line is two positive integers n, q.
Each of the next n lines is a string of lowercase letters representing si. The
next q line is two numbers xj, yj representing a set of queries.

Output format
Output q lines with an integer per line representing the answer.

Sample
Input sample 1

3 3
try
birkerem
sadasment
0 1
1 2
0 2

Sample output 1

3
1
2

Input example 2

10 20
aabbbbba
babaaaabb
aaaabaabba
abbabaaaa
aabbababa
aabbbbbbba
bbabaaabba
aaaababaa
abaaababab
aabbbbabb
1 7
1 8
7 8
7 7
4 4
9 1
5 5
5 8
2 9
8 2
0 7
4 8
5 8
3 0
6 2
2 5
2 2
7 1
5 2
1 1

Sample output 2

6
5
7
10
10
4
10
3
5
6
4
5
3
3
5
4
10
6
4
10

提示 范围 与 提示
1 ≤ n ≤ 50000, 1 ≤ n ≤ 100000, 0 ≤ xi, yi ≤ n - 1 1 \ le n \ le 50000,1 \ le n \ le 100000,0 \ le x_i, y_i \ le n -11n50000,1n100000,0xi,Yin1

solution

Very primitive violence: against yy every timey build a suffix automata, and thenxxx put it up to match,
sureTTT , GG needless to say

Optimization 1: Rebuild the suffix automata every time. It's too extravagant.
Consider changing yyy sorted in order, the sameyyy only build a suffix automata and use it repeatedly

Optimization 2: It is necessary to know that the matching time of the suffix automata is xxThe length of x
So in order to optimize the time, each time a suffix automaton is established for the long string, and the short string is used to run the matching

Optimization 3: Memorization! For the same xxx , there is no need to do wasteful work

Then it's AAA ! ! Time complexityO (nn) O(n\sqrt(n))O ( nn )


There is another way, but I didn’t write
Insert picture description here

code

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 100005
struct SAM {
    
    
	int len, fa;
	int son[26];
}t[maxn];
struct node {
    
    
	int x, id;
	node(){
    
    }
	node( int X, int Id ) {
    
    
		x = X, id = Id;
	}
};
vector < node > query[maxn];
vector < int > G[maxn];
int n, Q, cnt, last;
char s[maxn];
int ans[maxn];

void insert( int x ) {
    
    
	int pre = last, now = last = ++ cnt;
	t[now].len = t[pre].len + 1;
	while( pre && ! t[pre].son[x] ) t[pre].son[x] = now, pre = t[pre].fa;
	if( ! pre ) t[now].fa = 1;
	else {
    
    
		int u = t[pre].son[x];
		if( t[pre].len + 1 == t[u].len ) t[now].fa = u;
		else {
    
    
			int v = ++ cnt;
			t[v] = t[u];
			t[v].len = t[pre].len + 1;
			t[u].fa = t[now].fa = v;
			while( pre && t[pre].son[x] == u ) t[pre].son[x] = v, pre = t[pre].fa;
		}
	}
}

bool cmp( node x, node y ) {
    
    
	return x.x < y.x;
}

int solve( int u ) {
    
    
	int maxx = 0, len = 0, now = 1;
	for( int i = 0;i < G[u].size();i ++ ) {
    
    
		int v = G[u][i];
		while( t[now].fa && ! t[now].son[v] ) {
    
    
			now = t[now].fa;
			len = t[now].len;
		}
		if( t[now].son[v] ) {
    
    
			now = t[now].son[v];
			len ++;
		}
		maxx = max( maxx, len );
	}
	return maxx;
}

int main() {
    
    
	scanf( "%d %d", &n, &Q );
	for( int i = 0;i < n;i ++ ) {
    
    
		scanf( "%s", s );
		int len = strlen( s );
		for( int j = 0;j < len;j ++ )
			G[i].push_back( s[j] - 'a' );
	}
	for( int i = 1, u, v;i <= Q;i ++ ) {
    
    
		scanf( "%d %d", &u, &v );
		if( G[u].size() < G[v].size() ) swap( u, v );
		query[u].push_back( node( v, i ) );
	}
	for( int i = 0;i < n;i ++ ) {
    
    
		memset( t, 0, sizeof( t ) );
		cnt = last = 1;
		for( int j = 0;j < G[i].size();j ++ )
			insert( G[i][j] );
		sort( query[i].begin(), query[i].end(), cmp );
		int siz = query[i].size();
		for( int j = 0;j < siz;j ++ ) {
    
    
			ans[query[i][j].id] = solve( query[i][j].x );
			while( j < siz - 1 && query[i][j].x == query[i][j + 1].x ) {
    
    
				ans[query[i][j + 1].id] = ans[query[i][j].id];
				j ++;
			}
		}
	}
	for( int i = 1;i <= Q;i ++ )
		printf( "%d\n", ans[i] );
	return 0;
}

Guess you like

Origin blog.csdn.net/Emm_Titan/article/details/113873122