【ZOJ】3494 BCD Code AC自动机+数位DP

传送门:【ZOJ】3494 BCD Code


题目分析:用AC自动机预处理出从一个状态的一个数转移到下一个数时的状态,然后就可以用数位DP解决了。现在看来这题也水水的。。


代码如下:


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

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

const int MAXN = 2005 ;
const int mod = 1e9 + 9 ;

struct ac_automaton {
	int next[MAXN][2] ;
	int fail[MAXN] ;
	int word[MAXN] ;
	int cur ;
	int root ;
	int Q[MAXN] ;
	int head ;
	int tail ;

	int newnode () {
		rep ( i , 0 , 2 ) next[cur][i] = -1 ;
		word[cur] = 0 ;
		return cur ++ ;
	}

	void init () {
		cur = 0 ;
		root = newnode () ;
	}

	void insert ( char buf[] ) {
		int now = root ;
		for ( int i = 0 ; buf[i] ; ++ i ) {
			int x = buf[i] - '0' ;
			if ( next[now][x] == -1 ) next[now][x] = newnode () ;
			now = next[now][x] ;
		}
		word[now] = 1 ;
	}

	void build () {
		head = tail = 0 ;
		fail[root] = root ;
		rep ( i , 0 , 2 ) {
			if ( ~next[root][i] ) {
				fail[next[root][i]] = root ;
				Q[tail ++] = next[root][i] ;
			} else next[root][i] = root ;
		}
		while ( head != tail ) {
			int now = Q[head ++] ;
			word[now] |= word[fail[now]] ;
			rep ( i , 0 , 2 ) {
				if ( ~next[now][i] ) {
					fail[next[now][i]] = next[fail[now]][i] ;
					Q[tail ++] = next[now][i] ;
				} else next[now][i] = next[fail[now]][i] ;
			}
		}
	}
} ;

ac_automaton ac ;
int digit[MAXN] ;
char buf[MAXN] ;
int bcd[MAXN][10] ;
int dp[MAXN][MAXN] ;
int n ;

int get_next ( int now , int x ) {
	if ( ac.word[now] ) return -1 ;
	rev ( i , 3 , 0 ) {
		if ( ac.word[ac.next[now][( x >> i ) & 1]] ) return -1 ;
		now = ac.next[now][( x >> i ) & 1] ;
	}
	return now ;
}

int dfs ( int cur , int s , int limit , int pre_zero ) {
	if ( cur == -1 ) return 1 ;
	if ( !limit && dp[cur][s] != -1 ) return dp[cur][s] ;
	int ans = 0 , n = limit ? digit[cur] : 9 ;
	if ( pre_zero ) {
		ans += dfs ( cur - 1 , s , limit && digit[cur] == 0 , 1 ) ;
		if ( ans >= mod ) ans -= mod ;
	} else if ( ~bcd[s][0] ) {
		ans += dfs ( cur - 1 , bcd[s][0] , limit && digit[cur] == 0 , 0 ) ;
		if ( ans >= mod ) ans -= mod ;
	}
	For ( i , 1 , n ) if ( ~bcd[s][i] ) {
		ans += dfs ( cur - 1 , bcd[s][i] , limit && n == i , 0 ) ;
		if ( ans >= mod ) ans -= mod ;
	}
	if ( !limit && !pre_zero ) dp[cur][s] = ans ;
	return ans ;
}

int deal ( char buf[] , int len ) {
	rep ( i , 0 , len ) digit[i] = buf[len - i - 1] - '0' ;
	return dfs ( len - 1 , 0 , 1 , 1 ) ;
}

void solve () {
	int ans = 0 ;
	ac.init () ;
	clr ( dp , -1 ) ;
	scanf ( "%d" , &n ) ;
	For ( i , 1 , n ) {
		scanf ( "%s" , buf ) ;
		ac.insert ( buf ) ;
	}
	ac.build () ;
	rep ( i , 0 , ac.cur ) rep ( j , 0 , 10 ) bcd[i][j] = get_next ( i , j ) ;
	scanf ( "%s" , buf ) ;

	int len1 = strlen ( buf ) ;
	rev ( i , len1 - 1 , 0 ) {
		if ( buf[i] > '0' ) {
			-- buf[i] ;
			break ;
		} else buf[i] = '9' ;
	}
	ans -= deal ( buf , len1 ) ;
	
	scanf ( "%s" , buf ) ;
	int len2 = strlen ( buf ) ;
	ans += deal ( buf , len2 ) ;

	if ( ans < 0 ) ans += mod ;
	printf ( "%d\n" , ans ) ;
}

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


你可能感兴趣的:(HDU)