[BZOJ1212]-[HNOI2004]L语言-trie+DP

来源:互联网 发布:wings 知乎 编辑:程序博客网 时间:2024/05/27 18:17

说在前面

本来以为要建AC自动机,结果发现网上的题解都…直接上trie就可以了= =???
复杂度明明爆炸啊…


题目

BZOJ1212传送门

题面

一段文章T是由若干小写字母构成。一个单词W也是由若干小写字母构成。一个字典D是若干个单词的集合。 我们称一段文章T在某个字典D下是可以被理解的,是指如果文章T可以被分成若干部分,且每一个部分都是字典D中的单词。 例如字典D中包括单词{is, name, what, your},则文章whatisyourname是在字典D下可以被理解的,因为它可以分成4个单词:what, is, your, name,且每个单词都属于字典D。同理,文章‘whatisyouname’ 在字典D下不能被理解,不过这段文章的一个前缀whatis是可以被理解的。
现在给定一个字典D,你的程序需要判断若干段文章在字典D下是否能够被理解。 并给出其在字典D下能够被理解的最长前缀的位置。

输入输出格式

输入格式:
输入文件第一行是两个正整数n和m,表示字典D中有n个单词,且有m段文章需要被处理。 之后的n行每行描述一个单词,再之后的m行每行描述一段文章。 其中1<=n, m<=20,每个单词长度不超过10,每段文章长度不超过1e6

输出格式:
对于输入的每一段文章,你需要输出这段文章在字典D可以被理解的最长前缀的位置


解法

建好trie直接跑dp
令( bool ) dp[i]表示可以理解长度为i的前缀
如果当前dp[i]为true,就进trie去匹配,匹配到一个末尾节点就更新dp,刷表法


下面是自带大常数的代码

/**************************************************************    Problem: 1212    User: Izumihanako    Language: C++    Result: Accepted    Time:516 ms    Memory:2872 kb****************************************************************/ #include <cstdio>#include <cstring>#include <algorithm>using namespace stdint N , M , lena , maxlen , ans ;bool dp[1024*1024+5] ;char ss[25][25] , a[1024*1024+5] ;struct Node{    bool isend ;    char c ;    Node *ch[26] ;}*root ; void newNode( Node *&nd ){    nd = new Node() ;    nd->isend = false ;    memset( nd->ch , 0 , sizeof( nd->ch ) ) ;} void Insert( char *ts ){    int len = strlen( ts ) ;    maxlen = max( maxlen , len ) ;    Node *nd = root ;    for( int i = 0 ; i < len ; i ++ ){        int nxt = ts[i] - 'a' ;        if( !nd->ch[nxt] ){            newNode( nd->ch[nxt] ) ;            nd->ch[nxt]->c = ts[i] ;        }        nd = nd->ch[nxt] ;    }    nd->isend = true ;} inline void update( int pos ){    Node *nd = root ;    for( ; ; ){        //printf( "address(%d-[%c]) pos(%d) \n" , nd , nd->c , pos ) ;        int nxt = a[pos] - 'a' ;        if( !nd->ch[nxt] ) return ;        nd = nd->ch[nxt] ; pos ++ ;        if( nd->isend ) dp[pos] = true ;    }} void solve(){    for( register int i = 1 , j , tmp  ; i <= M ; ++ i ){        scanf( "%s" , a ) ; lena = strlen( a ) ;        dp[0] = 1 ; ans = 0 ;        for( j = 0 , tmp = 0 ; j < lena ; ++ j ){            if( dp[j] ){                update( j ) ;                tmp = 0 ; ans = j ;            } else {                ++ tmp ;                if( tmp == maxlen ) break ;            }        }        printf( "%d\n" , dp[lena] ? lena : ans ) ;        memset( dp , 0 , ( lena + 1 ) * sizeof( bool ) ) ;    }} int main(){    newNode( root ) ; root->c = 0 ;    scanf( "%d%d" , &N , &M ) ;    for( int i = 1 ; i <= N ; i ++ ){        scanf( "%s" , ss[i] ) ;        Insert( ss[i] ) ;           }    solve() ;}
原创粉丝点击