zoukankan      html  css  js  c++  java
  • hdu 2825

    题解:

    ac自动机+dp的题目

    差不多都一个套路

    记录枚举了i位,匹配到自动机上的x位,然后对于匹配了哪些单词状态压缩一下就可以了

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define mo 20090717 
    int dp[27][250][1030],w[1000],c[500][27];
    int cnt,fail[1000],pp[1030];
    char s[1000009];
    void insert(char s[1000009],int x)
    {
        int len=strlen(s),now=0;
        for (int i=0;i<len;i++)
        {
           int v=s[i]-'a';
           if (!c[now][v]) c[now][v]=++cnt;
           now=c[now][v];  
        }  
        w[now]=1<<(x-1);
    } 
    queue<int> q;
    void build()
    {
      for (int i=0;i<26;i++)
        if (c[0][i]) fail[c[0][i]]=0,q.push(c[0][i]);
      while (!q.empty())
      {
        int u=q.front();q.pop();
        for (int i=0;i<26;i++)
        {
          if (c[u][i])
          {
              fail[c[u][i]]=c[fail[u]][i];
              q.push(c[u][i]);
          }  else c[u][i]=c[fail[u]][i];
          w[c[u][i]]|=w[c[fail[u]][i]];
        }
      }
    }
    int main()
    {
      freopen("noip.in","r",stdin);
      freopen("noip.out","w",stdout);
      for (int i=1;i<=1028;i++)
      {
        int l=0;
        for (int j=0;j<=10;j++)
          if ((i>>j)%2==1) l++;
        pp[i]=l;
      }
      int n,m,k;
      while (cin>>n>>m>>k&&!(n==0&&m==0&&k==0))
      {
        memset(fail,0,sizeof(fail));
        memset(c,0,sizeof(c));
        memset(w,0,sizeof(w)); cnt=0;
        for (int i=1;i<=m;i++)
        {
          cin>>s; insert(s,i);
        }
        build();
        memset(dp,0,sizeof(dp));
        dp[0][0][0]=1;
        for (int i=0;i<=n;i++)
          for (int j=0;j<=cnt;j++)
            for (int k1=0;k1<=(1<<m)-1;k1++)
              if (dp[i][j][k1])
                for (int k2=0;k2<26;k2++)
                {
                  int u=c[j][k2];
                  dp[i+1][u][k1|w[u]]+=dp[i][j][k1];
                  dp[i+1][u][k1|w[u]]%=mo;
                  
                }
       /* for (int i=0;i<=n;i++)
          for (int j=0;j<=cnt;j++)
            for (int k1=1;k1<=(1<<m)-1;k1++)
              if (dp[i][j][k1])
                cout<<i<<" "<<j<<" "<<k1<<endl; */
        int ans=0;
        for (int i=0;i<=(1<<m)-1;i++)
          if (pp[i]>=k)
          for (int j=0;j<=cnt;j++) 
          {
            ans+=dp[n][j][i];
            ans%=mo;
          }
        cout<<ans<<" "<<cnt<<endl;
      }
      return 0;
    }
  • 相关阅读:
    Vue.js $nextTick
    JS---函数名和变量名重名
    for循环中嵌套setTimeout,执行顺序和结果该如何理解?
    Rocket MQ整体简介
    ant Desgn Pro Vue 修改 title
    STS插件创建springboot项目,pom第一行报unkown错误
    c# 读取二进制文件并转换为 16 进制显示
    c# Winform 调用可执行 exe 文件
    按字节读取txt文件缓存区大小设置多少比较好?
    天翼云服务开放端口
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/8453844.html
Copyright © 2011-2022 走看看