POJ1625-(AC自动机+DP+大数)

题解:跑一遍AC自动机,后直接在上面dp一维表示字符长度二维表示处于那个结点最后标记一下那些位置是危险结点不要转移过去即可,由于这题数据很大又没有取膜所以要用大数相加

#include
#include
#include
#include
#include
using namespace std;
const int mod = 1e8;
struct node{
    int len;
    int a[15];
    void operator +=(const node &x){
        int p = 0;
        for(int i =0; i <= len||i <= x.len; i++){
            int c = p+a[i]+x.a[i];
            a[i] = c%mod;
            p = c/mod;
        }
        len = max(len,x.len);
        if(p)
            a[++len] = p;
    }
    void print(){
        printf("%d",a[len]);
        for(int i = len-1; i >= 0; i--)
            printf("%08d",a[i]);
        puts("");
    }
};
int n,m,p;
struct tried{
    int ch[105][55];
    int f[105];
    int v[105];
    node dp[55][105];
    int mp[256];
    int sz;
    void init(){
        memset(ch[0],0,sizeof(ch[0]));
        memset(f,0,sizeof(f));
        memset(v,0,sizeof(v));
        memset(dp,0,sizeof(dp));
        dp[0][0].a[0] = 1;
        sz = 1;
    }
    void idx(char *s){
        int len = strlen(s);
        for(int i = 0; i < len; i++)
            mp[s[i]] = i;
    }
    void insert(char *s){
        int len = strlen(s);
        int u = 0;
        for(int i = 0; i < len; i++){
            int d = mp[s[i]];
            if(!ch[u][d]){
                memset(ch[sz],0,sizeof(ch[sz]));
                ch[u][d] = sz++;
            }
            u = ch[u][d];
        }
        v[u] = 1;
    }
    void getfail(){
        int u = 0;
        queueq;
        for(int d = 0; d < n; d++)
            if(ch[u][d])
                q.push(ch[u][d]);
        while(!q.empty()){
            u = q.front();
            q.pop();
            if(v[f[u]])
                v[u] = 1;
            for(int d = 0; d < n; d++){
                if(!ch[u][d]){
                    ch[u][d] = ch[f[u]][d];
                    continue;
                }
                int ret = ch[u][d];
                f[ret] = ch[f[u]][d];
                q.push(ret);
            }
        }
    }
    void work(){
        for(int i = 0; i < m; i++)
            for(int j = 0; j < sz; j++)
                if(!v[j])
                    for(int k = 0; k < n; k++){
                        int ret = ch[j][k];
                        if(!v[ret])
                            dp[i+1][ret] += dp[i][j];
                    }
        node ans;
        memset(ans.a,0,sizeof(ans.a));
        ans.len = 0;
        for(int j = 0; j < sz; j++)
            ans += dp[m][j];
        ans.print();
    }
}word;
char s[105];
int main(){
    while(scanf("%d%d%d",&n,&m,&p)!=EOF){
        word.init();
        scanf("%s",s);
        word.idx(s);
        for(int i = 1; i <= p; i++){
            scanf("%s",s);
            word.insert(s);
        }
        word.getfail();
        word.work();
    }
}


你可能感兴趣的:(DP,AC自动机)