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;
}

时间: 2024-12-22 04:17:33

HDU 2825的相关文章

hdu 2825 Wireless Password(AC自动机+状压DP)

题目链接:hdu 2825 Wireless Password 题目大意:N,M,K,M个字符串作为关键码集合,现在要求长度为N,包含K个以上的关键码的字符串有多少个. 解题思路:AC自动机+dp,滚动数组,因为关键码个数不会超过10个,所以我们用二进制数表示匹配的状态.dp[i][j][k] 表示到第i个位置,j节点,匹配k个字符串. #include <cstdio> #include <cstring> #include <queue> #include <

hdu 2825 aC自动机+状压dp

Wireless Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5640    Accepted Submission(s): 1785 Problem Description Liyuan lives in a old apartment. One day, he suddenly found that there

hdu 2825 Wireless Password(ac自动机&amp;dp)

Wireless Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4022    Accepted Submission(s): 1196 Problem Description Liyuan lives in a old apartment. One day, he suddenly found that there

hdu 2825 Wireless Password(ac自己主动机&amp;amp;dp)

Wireless Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4022    Accepted Submission(s): 1196 Problem Description Liyuan lives in a old apartment. One day, he suddenly found that there

HDU 2825 Wireless Password (AC自动机,DP)

http://acm.hdu.edu.cn/showproblem.php?pid=2825 Wireless Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4560    Accepted Submission(s): 1381 Problem Description Liyuan lives in a old a

HDU 2825 Wireless Password AC自动机+dp

训练赛第二场的I题,上完体育课回来就把这题过了,今天训练赛rank1了,还把大大队虐了,而且我还过了这道题 (虽然我也就过了这道题...),第一次在比赛中手写AC自动机还带dp的,心情大好. 给一个字符串集合,求包含该集合超过K个字符的,长度为L的字符串的个数. 显然是在AC自动机上跑dp,设dp[u][L][k]表示当前在结点u,还要走L步,当前状态为k的个数.一开始第三维表示的是包含k个字符串,但是题目要求不含重复的,那就只能状压了.转移为dp[u][L][k]+=dp[v][L-1][nk

hdu 2825 (Aho-Corasick &amp; 状压DP) - xgtao -

题目链接 给出m(m<=10)个模板串,问长度为n(n<=25)的字符串包含至少k个模板串的种类数,对20090717取模. 套路,有多个模板串考虑Aho-Corasick,因为想了很久找不到什么可行办法做,就考虑Dp,因为m<=10,所以可以有状压来检查当前状态下已经包含多少个模板串了,因为在一棵trie树上,那么定义状态也好定义,dp[len][id][s]表示长度为len时处在第id个节点并且状态为s,转移方程为dp[len+1][nextid][s|nexts] += dp[le

HDU 2825 Wireless Password(自动机+DP)

Problem Description Liyuan lives in a old apartment. One day, he suddenly found that there was a wireless network in the building. Liyuan did not know the password of the network, but he got some important information from his neighbor. He knew the p

HDU 2825 Wireless Password (AC自动机 + 状态压缩DP)

题目链接:Wireless Password 解析:给 m 个单词构成的集合,统计所有长度为 n 的串中,包含至少 k 个单词的方案数. AC自动机 + 状态压缩DP. DP[i][j][k]:长度为i的字符串匹配到状态j且包含k个magic word的可能字符串个数. AC代码: #include <algorithm> #include <iostream> #include <cstdio> #include <queue> #include <