zoukankan      html  css  js  c++  java
  • HDU 2825 AC自动机+DP

    题意:一个密码,长度为 n,然后有m个magic words,这个密码至少由k个magic words组成。

    问这个密码可能出现的总数。

    思路:首先构造AC自动机,由于m很小,才10 ,我们可以使用二进制来表示每个magic words的使用情况。

    对于dp[i][j][k],表示长度为i 时,匹配到j这个节点,当前选取的magic words是k 状态时的最大数量。

    #include <set>
    #include <map>
    #include <stack>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <iomanip>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define Max 2505
    #define FI first
    #define SE second
    #define ll long long
    #define PI acos(-1.0)
    #define inf 0x3fffffff
    #define LL(x) ( x << 1 )
    #define bug puts("here")
    #define PII pair<int,int>
    #define RR(x) ( x << 1 | 1 )
    #define mp(a,b) make_pair(a,b)
    #define mem(a,b) memset(a,b,sizeof(a))
    #define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
    using namespace std;
    #define MOD 20090717
    #define N 1111111
    int n , m , k ;
    int cnt ;
    struct AC_AUTO {
        int next[26] ;
        int fail ;
        int st ;
        void init() {
            mem(next ,0) ;
            fail = -1 ;
            st = 0 ;
        }
    } a[500000];
    int vis[111111] ;
    void show(int now) {
        vis[now] = 1 ;
        cout << now << " " << a[now].fail << endl;
        for (int i = 0 ; i < 26 ; i ++ ) {
            if(a[now].next[i] != 0 && !vis[a[now].next[i]]) {
                show(a[now].next[i]) ;
            }
        }
    }
    void insert(char *s,int k) {
        int p = 0 ;
        for(int i = 0 ; s[i] ; i ++) {
            int t = s[i] - 'a' ;
            if(a[p].next[t] == 0) {
                a[cnt].init() ;
                a[p].next[t] = cnt ++ ;   
            }
            p = a[p].next[t] ;
        }
        a[p].st |= (1 << k) ;
    }
    int q[111111] ;
    void ac_bfs() {
        int i,head = 0,tail = 0;
        q[tail ++]=0;
        while(head < tail) {
            int front = q[head ++];
            for(i = 0; i < 26 ; i ++) {
                if(a[front].next[i] == 0) {///
                    if(front == 0)a[front].next[i] = 0 ;
                    else a[front].next[i] = a[a[front].fail].next[i] ;
                } else {
                    int p = a[front].fail ;
                    while(p != -1) {
                        if(a[p].next[i] != 0) {
                            a[a[front].next[i]].fail = a[p].next[i] ;
                            a[a[front].next[i]].st |= a[a[p].next[i]].st ;
                            break ;
                        }
                        p = a[p].fail ;
                    }
                    if(p == -1)a[a[front].next[i]].fail = 0 ;
                    q[tail ++] = a[front].next[i] ;
                }
            }
        }
    }
    int dp[26][200][1 << 10] ;
    
    int solve() {
        for (int i = 0 ; i <= n ; i ++ )
            for (int j = 0 ; j <= cnt ; j ++ )
                for (int x = 0 ; x <= 1 << m ; x ++ )
                    dp[i][j][x] = 0 ;
        dp[0][0][0] = 1 ;
        for (int i = 0 ; i < n ; i ++ )//长度为i时
            for (int j = 0 ; j < cnt ; j ++ )//在第j个节点
                for (int x = 0 ; x < 1 << m ; x ++) { //第x个状态
                    if(!dp[i][j][x])continue ;
                    for (int y = 0 ; y < 26 ; y ++ ) { //字母y
                        int newj = a[j].next[y] ;
                        int newst = x | a[newj].st ;
                        dp[i + 1][newj][newst] = (dp[i][j][x] + dp[i + 1][newj][newst] ) % MOD ;
                    }
                }
        int ans = 0 ;
        for (int i = 0 ; i < 1 << m ; i ++ ) {
            int ret = 0 ;
            int d = i ;
            for (; d ; d -= d & (-d) , ret ++) ;
            if(ret < k )continue ;
            for (int j = 0 ; j < cnt ; j ++ ) {
                ans = (ans + dp[n][j][i]) % MOD ;
            }
        }
        return ans ;
    }
    char in[111] ;
    int main() {
        while(cin >> n >> m >> k, (n + m + k)) {
            a[0].init() ;
            cnt = 1 ;
            for (int i = 0 ; i < m ; i ++ ) {
                scanf("%s",in) ;
                insert(in , i) ;
            }
            ac_bfs() ;
            printf("%d
    ",solve()) ;
        }
        return 0 ;
    }
    


  • 相关阅读:
    [转]HSPICE 使用流程
    [转]到底怎么样才叫看书?——上篇
    js弹出层
    mvc自定义扩展控件
    yield 关键字
    mvc学习地址
    C# 将List中的数据导入csv文件中
    Asp.net 下载文件(弹出对话框的形式)
    Asp.net中用Jquery实现Ajax回调后台方法
    SharePoint中获取当前登录的用户名
  • 原文地址:https://www.cnblogs.com/riskyer/p/3285839.html
Copyright © 2011-2022 走看看