HDU 2825 Wireless Password(AC自动机 + 状压DP)题解

题意:m个密码串,问你长度为n的至少含有k个不同密码串的密码有几个

思路:状压一下,在build的时候处理fail的时候要用 | 把所有的后缀都加上。

代码:

#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 100 + 5;
const int M = 50 + 5;
const ull seed = 131;
const double INF = 1e20;
const int MOD = 20090717;
int n, m, K;
int dp[28][maxn][1100];
int num[1100];
struct Aho{
    struct state{
        int next[26];
        int fail, cnt;
    }node[maxn];
    int size;
    queue<int> q;

    void init(){
        size = 0;
        newtrie();
        while(!q.empty()) q.pop();
    }

    int newtrie(){
        memset(node[size].next, 0, sizeof(node[size].next));
        node[size].cnt = node[size].fail = 0;
        return size++;
    }

    void insert(char *s, int id){
        int len = strlen(s);
        int now = 0;
        for(int i = 0; i < len; i++){
            int c = s[i] - 'a';
            if(node[now].next[c] == 0){
                node[now].next[c] = newtrie();
            }
            now = node[now].next[c];
        }
        node[now].cnt = 1 << id;
    }

    void build(){
        node[0].fail = -1;
        q.push(0);

        while(!q.empty()){
            int u = q.front();
            q.pop();
            if(node[node[u].fail].cnt && u) node[u].cnt |= node[node[u].fail].cnt;
            for(int i = 0; i < 26; i++){
                if(!node[u].next[i]){
                    if(u == 0)
                        node[u].next[i] = 0;
                    else
                        node[u].next[i] = node[node[u].fail].next[i];
                }
                else{
                    if(u == 0) node[node[u].next[i]].fail = 0;
                    else{
                        int v = node[u].fail;
                        while(v != -1){
                            if(node[v].next[i]){
                                node[node[u].next[i]].fail = node[v].next[i];
                                break;
                            }
                            v = node[v].fail;
                        }
                        if(v == -1) node[node[u].next[i]].fail = 0;
                    }
                    q.push(node[u].next[i]);
                }
            }
        }
    }

    void query(){
        for(int i = 0; i <= n; i++){
            for(int j = 0; j < size; j++){
                for(int k = 0; k < (1 << m); k++){
                    dp[i][j][k] = 0;
                }
            }
        }
        for(int i = 0; i < 26; i++){
            if(node[node[0].next[i]].cnt){
                int v = node[node[0].next[i]].cnt;
                dp[1][node[0].next[i]][v]++;
//                printf("* %d %d %d\n", 1, node[0].next[i], v);
            }
            else
                dp[1][node[0].next[i]][0]++;
        }
        for(int i = 1; i < n; i++){
            for(int j = 0; j < size; j++){
                for(int k = 0; k < (1 << m); k++){
                    if(dp[i][j][k] == 0) continue;
                    for(int l = 0; l < 26; l++){
                        if(node[node[j].next[l]].cnt){
                            int v = node[node[j].next[l]].cnt;
                            dp[i + 1][node[j].next[l]][k | v] = (dp[i + 1][node[j].next[l]][k | v] + dp[i][j][k]) % MOD;
                        }
                        else{
                            dp[i + 1][node[j].next[l]][k] = (dp[i + 1][node[j].next[l]][k] + dp[i][j][k]) % MOD;
                        }
                    }
                }
            }
        }
        int ans = 0;
        for(int i = 0; i < size; i++){
            for(int j = 0; j < (1 << m); j++){
                if(num[j] >= K) ans = (ans + dp[n][i][j]) % MOD;
            }
        }
        printf("%d\n", ans);
    }

}ac;
char s[100];
int main(){
    for(int i = 0; i < 1100; i++){
        int temp = 0, x = i;
        while(x){
            temp += x & 1;
            x >>= 1;
        }
        num[i] = temp;
    }
    while(~scanf("%d%d%d", &n, &m, &K) && n + m + K){
        ac.init();
        for(int i = 0; i < m; i++){
            scanf("%s", s);
            ac.insert(s, i);
        }
        ac.build();
        ac.query();
    }
    return 0;
}

 

posted @ 2019-07-15 11:30  KirinSB  阅读(169)  评论(0编辑  收藏  举报