HDU 2825

下午连续看了两题的AC自动机+DP题,发现都有点规律了,都是由trie图循环赋值,按照结点一步步向外推的,而且状态设的也很相似。。。

dp[i][j][k],一开始以为至少k个是可以相同的,其实这k个串应该是不同的,于是就可以按照二进制压缩这M个串,1表示选上了这个串。注意一下fail指向的结点要与当前自身的选串的状态或上就可以了。为当前处于i状态,前j个字符。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <string.h>
#include <queue>
#include <cmath>
#include <map>
#include <vector>
#define LL  __int64
using namespace std;

const int dictsize=26;
const int MOD =20090717;
const int Maxn=150;
const int root=0;
const int state=(1<<10)-1;
int head,tail;
int que[Maxn];
struct Node {
    int fail,next[dictsize];
    int tag;
    void initial(){
        fail=-1,tag=false;
        for(int i=0;i<dictsize;i++) next[i]=-1;
    }
}trie[Maxn];
int tot,n,m,l;
char str[15];
int dp[Maxn][26][state+1];

void Insert_trie(int s){
    int p=0,i=0;
    while(str[i]){
        if(trie[p].next[str[i]-'a']==-1) trie[p].next[str[i]-'a']=++tot;
        p=trie[p].next[str[i]-'a'];
        i++;
    }
    trie[p].tag=(1<<s);
}
 
void build_ac(){
    que[tail++]=root;
    int i,tmp,p;
    while(head!=tail){
        tmp=que[head++];
        p=-1;
        for(int i=0;i<dictsize;i++){
            if(trie[tmp].next[i]!=-1){
                if(tmp==root) trie[trie[tmp].next[i]].fail=root;
                else{
                    p=trie[tmp].fail;
                    while(p!=-1){
                        if(trie[p].next[i]!=-1){
                            trie[trie[tmp].next[i]].fail=trie[p].next[i];
                            break;
                        }
                        p=trie[p].fail;
                    }
                    if(p==-1){
                        trie[trie[tmp].next[i]].fail=root;
                    }
                }
                trie[trie[tmp].next[i]].tag|=trie[trie[trie[tmp].next[i]].fail].tag;
                que[tail++]=trie[tmp].next[i];
            }
            else{   //trie[tmp].next[i]==-1
                if(tmp==root) trie[tmp].next[i]=root;
                else{
                    p=trie[tmp].fail;
                    while(p!=-1){
                        if(trie[p].next[i]!=-1){
                            trie[tmp].next[i]=trie[p].next[i];
                            break;
                        }
                        p=trie[p].fail;
                    }
                    if(p==-1){
                        trie[tmp].next[i]=root;
                    }
                }
            }
        }
    }
}

bool ok(int s,int k){
    int c=0;
    while(s){
        if(s&1) c++;
        s>>=1;
    }
    if(c>=k) return true;
    return false;
}

int main(){
    while(scanf("%d%d%d",&n,&m,&l)&&n||m||l){
        tot=head=tail=0;
        for(int i=0;i<110;i++)
        trie[i].initial();
        for(int i=0;i<m;i++){
            scanf("%s",str);
            Insert_trie(i);
        }
        build_ac();
        memset(dp,0,sizeof(dp));
        dp[0][0][0]=1;
        int alstate=(1<<m)-1,son;
        for(int j=0;j<=n;j++){
            for(int i=0;i<=tot;i++){
                for(int k=0;k<=alstate;k++){
                    if(dp[i][j][k]>0){
                        for(int e=0;e<dictsize;e++){
                            son=trie[i].next[e];
                            dp[son][j+1][trie[son].tag|k]=(dp[son][j+1][trie[son].tag|k]+dp[i][j][k])%MOD;
                        }
                    }
                }
            }
        }
        int ans=0;
        for(int i=0;i<=tot;i++){
            for(int k=0;k<=alstate;k++){
                if(ok(k,l)){
                    ans=(ans+dp[i][n][k])%MOD;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2015-03-03 19:59  chenjunjie1994  阅读(157)  评论(0编辑  收藏  举报