[codeforces 86C]补全AC自动机上DP
2017-10-25 19:28
429 查看
说在前面
microsoftEdge上使用markdown会出现各种排版bug,使用体验极差!
题目
codeforces 86C传送门题目大意:给定一些长度不超过10的字符串,字符串个数不超过10,询问完全用这些字符串构成(可以重叠,拼接)的长度为N的字符串的方案数。
样例:
Input
6 2
CAT
TACT
Output
2
解法
这道题是dp,me现在仍然没想清楚为什么会这样定义dp数组..首先对于题目给定的串,建立补全AC自动机。
定义dp[i][j][k]表示现在已经选到了第i个字符,在AC自动机上的j号结点,当前已选串的末尾k个还未被包含在某一个给定字符串内。
预处理每个AC自动机节点作为某个给定字符串的末尾字符时,给定字符串最长的长度,记为Tlen。(相当于是一直跳fail,如果遇到一个节点有isend标记,就用那个串长更新当前点的长度)。
转移:
对于dp[i][j][k]
如果下一个节点的Tlen大于k+1(相当于把之前没有包含的包含了),那么转移到dp[i+1][j`][0]
不然转移到dp[i+1][j`][k+1]
自带大常数的代码
#include <cstdio> #include <cstring> #include <algorithm> using namespace std ; const int mmod = 1e9+9 ; int N , M , len , dp[1001][101][11] , ans ; char ss[20] ; struct Node{ int maxLen , id ; int cc ; Node *ch[4] , *fail ; Node(){ maxLen = 0 ; ch[0] = ch[1] = ch[2] = ch[3] = fail = NULL ; } }w[500] , *root , *tw = w ; void Insert( ){ Node *nd = root ; for( int i = 0 ; i < len ; i ++ ){ if( !nd->ch[ ss[i] ] ){ nd->ch[ ss[i] ] = ++tw ; nd->ch[ ss[i] ]->id = tw - w ; nd->ch[ ss[i] ]->cc = ss[i] ; } nd = nd->ch[ ss[i] ] ; } nd->maxLen = len ; } Node *q[500] ; int ba , fr , vis[505] ; void getFail(){ ba = 0 ; fr = 1 ; root->fail = root ; q[++ba] = root ; vis[ root->id ] = true ; while( ba >= fr ){ Node *u = q[fr++] ; for( int i = 0 ; i < 4 ; i ++ ){ Node *v = u->ch[i] ; if( !v || v->fail ) continue ; if( u == root ) v->fail = root ; else{ Node *p = u->fail ; while( !p->ch[i] && p != root ) p = p->fail ; v->fail = ( p->ch[i] ? p->ch[i] : root ) ; v->maxLen = max( v->maxLen , v->fail->maxLen ) ; } for( int j = 0 ; j < 4 ; j ++ ) if( !v->ch[j] ) v->ch[j] = v->fail->ch[j] ; q[++ba] = v ; } } } void solve( ){ dp[0][1][0] = 1 ; for( int i = 0 ; i < N ; i ++ ){ for( int j = 1 ; j <= tw - w ; j ++ ){ Node *nd = &w[j] ; for( int k = 0 ; k <= 10 ; k ++ ){ if( !dp[i][j][k] ) continue ; for( int sn = 0 ; sn < 4 ; sn ++ ){ Node *nxt = nd->ch[sn] ; if( !nxt ) continue ; if( nxt->maxLen >= k + 1 ) dp[i+1][nxt->id][0] = ( dp[i+1][nxt->id][0] + dp[i][j][k] ) %mmod ; else if( k != 10 ) dp[i+1][nxt->id][k+1] = ( dp[i+1][nxt->id][k+1] + dp[i][j][k] ) %mmod ; } } } } for( int j = 1 ; j <= tw - w ; j ++ ) ans = ( ans + dp [j][0] ) %mmod ; printf( "%d" , ans ) ; } int main(){ //freopen( "protect.in" , "r" , stdin ) ; //freopen( "protect.out", "w" , stdout) ; scanf( "%d%d" ,&N , &M ) ; root = ++tw ; root->id = tw - w ; for( int i = 1 ; i <= M ; i ++ ){ scanf( "%s" , ss ) ; len = strlen( ss ) ; for( int j = 0 ; j < len ; j ++ ) if( ss[j] == 'A' ) ss[j] = 0 ; else if( ss[j] == 'T' ) ss[j] = 1 ; else if( ss[j] == 'C' ) ss[j] = 2 ; else if( ss[j] == 'G' ) ss[j] = 3 ; Insert() ; } getFail( ) ; solve() ; }
相关文章推荐
- Codeforces 86C Genetic engineering(AC自动机+DP)
- AC自动机+dp(CodeForces - 86C )
- Codeforces 86C Genetic engineering (AC自动机+dp)
- BZOJ1030 [JSOI2007]文本生成器 补全AC自动机+简单DP
- hdu4758 Walk Through Squares (AC自动机+DP)
- ZOJ 3494 BCD Code(AC自动机+数位DP)
- HDU2825 Wireless Password [AC自动机+压缩DP]
- nefu 1267 挑战字符串(AC自动机+dp)
- Rikka with String HDU - 6086 多校#5 AC自动机DP
- hdu2457DNA repair(ac自动机+dp)
- HDOJ 4057 - Rescue the Rabbit 简单的AC自动机+状态压缩DP
- HDU4758 Walk Through Squares(AC自动机+状压DP)
- HDU 2296 Ring(AC自动机+DP)
- POJ3691:DNA repair(AC自动机+DP)
- hdu 4057 Rescue the Rabbit(AC自动机+状压dp)
- UVA 11468 Substring(AC自动机+dp)
- zoj 3494 BCD Code (ac自动机+数位dp)
- 【HDU6086】Rikka with String-AC自动机+状压DP
- BZOJ 2553: [BeiJing2011]禁忌(AC自动机+期望DP+矩阵快速幂)
- POJ 2778 DNA Sequence(AC自动机+DP)