【HDU】5164 Matching on Array 【AC自动机】

传送门:【HDU】5164 Matching on Array 【AC自动机】


题目分析:系数通过两两相除或者log后差分可以消除,然后就变成了匹配问题了,时间允许,可以用kmp,如果时间严格,就用ac自动机,ac自动机需要做一些改造,我想到的就是每个节点用map存指向下一个节点的指针,为了准确起见,用两两相除得到的分数形式作为关键字,因为数大小在1~10000内,所以可以用分子*10001+分母或者分母*10001+分子当关键字,这样一个关键字就够了,然后ac自动机不能用主流的写法(处理掉next指针),用时间换空间,next和fail都用一层while来推。具体可以自己想想怎么实现哈,我好不容易才从mle的囚牢中脱逃- -。

我的代码现在c++AC,g++CE,不知道为什么T T,好心人可以帮我找找为什么会这样吧~


代码如下:


#include <cmath>
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

typedef long long LL ;

#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )

const int MAXN = 1000005 ;

LL ans ;

int gcd ( int a , int b ) {
	return b ? gcd ( b , a % b ) : a ;
}

struct AC_automation {
	map < int , int > mp[MAXN] ;
	map < int , int > :: iterator it ;
	int fail[MAXN] ;
	int end[MAXN] ;
	int Q[MAXN] , head , tail ;
	int root ;
	int p ;

	int newnode () {
		mp[p].clear () ;
		end[p] = 0 ;
		return p ++ ;
	}

	void init () {
		p = 0 ;
		ans = 0 ;
		root = newnode () ;
	}

	void insert ( int s[] , int n ) {
		int now = root ;
		rep ( i , 1 , n ) {
			int g = gcd ( s[i] , s[i + 1] ) ;
			int t = s[i] / g * 10001 + s[i + 1] / g ;
			if ( !mp[now].count ( t ) ) mp[now][t] = newnode () ;
			now = mp[now][t] ;
		}
		++ end[now] ;
	}

	void build () {
		head = tail = 0 ;
		fail[root] = root ;
		for ( it = mp[root].begin () ; it != mp[root].end () ; ++ it ) {
			fail[it->second] = root ;
			Q[tail ++] = it->second ;
		}
		while ( head != tail ) {
			int now = Q[head ++] ;
			end[now] += end[fail[now]] ;
			for ( it = mp[now].begin () ; it != mp[now].end () ; ++ it ) {
				int x = fail[now] , flag = 0 ;
				while ( x != root ) {
					if ( mp[x].count ( it->first ) ) {
						fail[it->second] = mp[x][it->first] ;
						flag = 1 ;
						break ;
					}
					x = fail[x] ;
				}
				if ( x == root && mp[x].count ( it->first ) ) {
					fail[it->second] = mp[x][it->first] ;
					flag = 1 ;
				}
				if ( !flag ) fail[it->second] = root ;
				Q[tail ++] = it->second ;
			}
		}
	}

	void query ( int s[] , int n ) {
		int now = root ;
		rep ( i , 1 , n ) {
			int g = gcd ( s[i] , s[i + 1] ) ;
			int t = s[i] / g * 10001 + s[i + 1] / g ;
			int x = now , flag = 0 ;
			while ( x != root ) {
				if ( mp[x].count ( t ) ) {
					now = mp[x][t] ;
					flag = 1 ;
					break ;
				}
				x = fail[x] ;
			}
			if ( x == root && mp[x].count ( t ) ) {
				now = mp[x][t] ;
				flag = 1 ;
			}
			if ( !flag ) now = root ;
			ans += end[now] ;
		}
	}
} ;

AC_automation ac ;
int s[100005] , p[300005] ;
int n , m , q ;


void solve () {
	ans = 0 ;
	ac.init () ;
	scanf ( "%d%d" , &n , &q ) ;
	For ( i , 1 , n ) scanf ( "%d" , &s[i] ) ;
	while ( q -- ) {
		scanf ( "%d" , &m ) ;
		For ( i , 1 , m ) scanf ( "%d" , &p[i] ) ;
		if ( m > 1 ) ac.insert ( p , m ) ;
		else ans += n ;
	}
	ac.build () ;
	ac.query ( s , n ) ;
	printf ( "%I64d\n" , ans ) ;
}

int main () {
	int T ;
	scanf ( "%d" , &T ) ;
	while ( T -- ) solve () ;
	return 0 ;
}


你可能感兴趣的:(HDU)