• HDU-2825Wireless Password(AC自动机+状压DP)


    HDU-2825

    题意:多组输入,每组给定n,m,k三个整数,一个长度为n的字符串,由m个子字符串中的至少k个组成,求一共有多少种排列组合方法,结果需要mod

    解题思路:

    ac自动机上跑状压DP

    dp[i+1][nx][k|val[nx]] = (dp[i+1][nx][k|val[nx]]+dp[i][j][k])%mod

    第一维表示当前主串长度,第二维表示自动机上的节点,第三维用二进制表示集合中存在哪几个字符串。需要利用辅助数组num预处理二进制下数字x的1的个数,即包含字符串的个数

    代码:

    //#pragma GCC optimize(3)
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<deque>
    #include<queue>
    #include<map>
    #include<set>
    #include<stack>
    #include<string>
    #include<sstream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cctype>
    #include<cassert>
    #include<cstdlib>
    #include<utility>
    #include<iterator>
    #include<iomanip>
    
    using namespace std;
    #define lowbit(x) x&(-x)
    typedef long long ll;
    typedef long double lb;
    typedef unsigned long long ull;
    int read();
    const double PI = acos(-1.0);
    const int maxn = 110;
    const int mod = 20090717;
    int n,m,cnt;
    int tot;
    struct node
    {
        int nx[26];
        int val;
        int fail;
    }ac[maxn];
    int num[1<<11];
    int dp[30][maxn][1<<10];//长度,节点,状态
    int ans;
    char s[50];
    void init()
    {
        tot = 0;
        for(int i = 0;i<maxn;i++)
        {
            memset(ac[i].nx,0,sizeof(ac[i].nx));
            ac[i].fail = 0;
            ac[i].val = 0;
        }
    }
    void getnum()
    {
        for(int i = 0;i<(1<<10);i++)
        {
            num[i] = 0;
            for(int j = 0;j<10;j++)
            {
                if(i&(1<<j))
                {
                    num[i]++;
                }
            }
        }
    }
    void insert(char *s,int id)
    {
        int p = 0;
        int len = strlen(s);
        for(int i = 0; i<len; i++)
        {
            int ch = s[i]-'a';
            if(!ac[p].nx[ch])
            {
                ac[p].nx[ch] = ++tot;
            }
            p = ac[p].nx[ch];
        }
        ac[p].val|=(1<<id);
    }
    void getfail()
    {
        queue<int> q;
        for(int i = 0;i<26;i++)
        {
            if(ac[0].nx[i])
            {
                ac[ac[0].nx[i]].fail = 0;
                q.push(ac[0].nx[i]);
            }
        }
        while(!q.empty())
        {
            int r = q.front();
            q.pop();
            ac[r].val|=ac[ac[r].fail].val;
            for(int i = 0;i<26;i++)
            {
                if(!ac[r].nx[i])
                {
                    ac[r].nx[i] = ac[ac[r].fail].nx[i];
                    
                }else
                {
                    ac[ac[r].nx[i]].fail = ac[ac[r].fail].nx[i];
                    q.push(ac[r].nx[i]); 
                }
    
            }
        }
    }
    int gao()
    {
        memset(dp,0,sizeof(dp));
        dp[0][0][0] = 1;
        for(int i = 0;i<n;i++){
            for(int j = 0;j<=tot;j++){
                for(int k = 0;k<(1<<m);k++){
                      if(dp[i][j][k])
                      {
                          for(int c = 0;c<26;c++)
                          {
                             int nowi = i+1;
                             int nowj = ac[j].nx[c];
                             int nowk = k|ac[nowj].val;
                             dp[nowi][nowj][nowk] += dp[i][j][k];
                             dp[nowi][nowj][nowk]%=mod;
                          }
                      }
                }
            }
        }
        ans = 0;
        for(int i =0;i<(1<<m);i++)
        {
            if(num[i]>=cnt)
            {
                for(int j = 0;j<=tot;j++)
                {
                    ans = (ans+dp[n][j][i])%mod;
                }
            }
        }
        return ans%mod;
    }
    int main() {
    
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        getnum();
        while(scanf("%d%d%d",&n,&m,&cnt)!=EOF)
        {
            if(n==0&&m==0&&cnt==0)break;
            init();
            for(int i = 0;i<m;i++)
            {
                scanf("%s",&s);
                insert(s,i);
            }
            getfail();
            printf("%d
    ",gao());
        }
        
        
        return 0;
    }
    
    inline int read() {
        int x = 0, w = 0;
        char ch = 0;
        while (!isdigit(ch)) {
            w |= (ch == '-');
            ch = getchar();
        }
        while (isdigit(ch)) {
            x = (x << 3) + (x << 1) + (ch ^ 48);
            ch = getchar();
        }
        return w ? -x : x;
    }
    
  • 相关阅读:
    实体机可以ping通虚拟机,虚拟机ping不通实体机
    实体机可以ping通虚拟机,虚拟机ping不通实体机
    eclipse快捷键
    eclipse快捷键
    利用信号捕捉函数回收子进程
    进程间通信_信号
    进程间通信_管道
    创建子进程
    系统编程入门
    JPG库移植与使用
  • 原文地址:https://www.cnblogs.com/cloudplankroader/p/11735977.html
Copyright © 2020-2023  润新知