zoukankan      html  css  js  c++  java
  • HDU2825 Wireless Password(AC自动机+状压DP)

    题目问长度n至少包含k个咒语的字符串有多少个。也是比较入门的题。。

    • dp[i][j][S]表示长度i(在自动机上转移k步)且后缀状态为自动机上第j个结点且当前包含咒语集合为S的方案数
    • dp[0][0][0]=1
    • 还是用我为人人转移,AC自动机上的结点要多一个域表示这个结点所代表咒语前缀包含的咒语集合。
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue>
     4 using namespace std;
     5 int tn,ch[111][26],fail[111],flag[111];
     6 void insert(char *s,int k){
     7     int x=0;
     8     for(int i=0; s[i]; ++i){
     9         int y=s[i]-'a';
    10         if(ch[x][y]==0) ch[x][y]=++tn;
    11         x=ch[x][y];
    12     }
    13     flag[x]|=1<<k;
    14 }
    15 void init(){
    16     memset(fail,0,sizeof(fail));
    17     queue<int> que;
    18     for(int i=0; i<26; ++i){
    19         if(ch[0][i]) que.push(ch[0][i]);
    20     }
    21     while(!que.empty()){
    22         int x=que.front(); que.pop();
    23         for(int i=0; i<26; ++i){
    24             if(ch[x][i]) que.push(ch[x][i]),fail[ch[x][i]]=ch[fail[x]][i],flag[ch[x][i]]|=flag[ch[fail[x]][i]];
    25             else ch[x][i]=ch[fail[x]][i];
    26         }
    27     }
    28 }
    29 int getCnt(int s){
    30     int res=0;
    31     for(int i=0; i<10; ++i){
    32         if((s>>i)&1) ++res;
    33     }
    34     return res;
    35 }
    36 int d[26][111][1<<10];
    37 int main(){
    38     char str[11];
    39     int n,m,k;
    40     while(~scanf("%d%d%d",&n,&m,&k) && (n||m||k)){
    41         tn=0;
    42         memset(ch,0,sizeof(ch));
    43         memset(flag,0,sizeof(flag));
    44         for(int i=0; i<m; ++i){
    45             scanf("%s",str);
    46             insert(str,i);
    47         }
    48         init();
    49         memset(d,0,sizeof(d));
    50         d[0][0][0]=1;
    51         for(int i=0; i<n; ++i){
    52             for(int j=0; j<=tn; ++j){
    53                 for(int k=0; k<(1<<m); ++k){
    54                     if(d[i][j][k]==0) continue;
    55                     for(int y=0; y<26; ++y){
    56                         d[i+1][ch[j][y]][k|flag[ch[j][y]]]+=d[i][j][k];
    57                         d[i+1][ch[j][y]][k|flag[ch[j][y]]]%=20090717;
    58                     }
    59                 }
    60             }
    61         }
    62         int res=0;
    63         for(int i=0; i<=tn; ++i){
    64             for(int j=0; j<(1<<m); ++j){
    65                 if(getCnt(j)<k) continue;
    66                 res+=d[n][i][j];
    67                 res%=20090717;
    68             }
    69         }
    70         printf("%d
    ",res);
    71     }
    72     return 0;
    73 }
  • 相关阅读:
    基本类型和包装类对象使用 == 和 equals进行比较的结果?
    ==和equals的区别是什么?
    JDK和JRE有什么区别?
    Java自学指南三、入门视频优先
    Java自学指南二、后端开发全景图与快速入门
    Java自学指南一、找一个开始并能坚持下去的理由
    什么是&#160;happens-before 原则?
    什么是 Java 内存模型?
    Java 中有哪些无锁技术来解决并发问题?如何使用?
    什么是活锁和饥饿?
  • 原文地址:https://www.cnblogs.com/WABoss/p/5170699.html
Copyright © 2011-2022 走看看