传送门:【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 ; }