AC自动机+dp+大数 poj1625

30 篇文章 0 订阅
9 篇文章 0 订阅

传送门:点击打开链接

题意:告诉你有哪些字符可以用,然后再告诉你哪些单词不能出现,要你求长度为m的字符串只由给你的字符组成,但是不能出现那些单词的种类数。

思路:..一分析就发现,,貌似爆long long了,,醉了。。总的思路和那个DNA的思路是一样的,用AC自动机完成了矩阵的转移,很逆天的压缩了状态。。除了大数其他和那题基本一样的可以去看看那题..

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;

/*MX为总长度*/
const int MX = 2e2 + 5;
const int P = 128;

int G[MX][MX];

struct AC_machine {
    int rear, root, ID[MX], s;
    int Next[MX][P], Fail[MX], End[MX];

    void Init(char *A) {
        rear = 0;
        s = strlen(A);
        for(int i = 0; i < s; i++) {
            ID[A[i]] = i;
        }
        root = New();
    }

    int New() {
        End[rear] = 0;
        for(int i = 0; i < s; i++) {
            Next[rear][i] = -1;
        }
        return rear++;
    }

    void Add(char *A) {
        int now = root, n = strlen(A);
        for(int i = 0; i < n; i++) {
            int id = ID[A[i]];
            if(Next[now][id] == -1) {
                Next[now][id] = New();
            }
            now = Next[now][id];
        }
        End[now] = 1;
    }

    void Build() {
        queue<int>Q;
        Fail[root] = root;
        for(int i = 0; i < s; i++) {
            if(Next[root][i] == -1) {
                Next[root][i] = root;
            } else {
                Fail[Next[root][i]] = root;
                Q.push(Next[root][i]);
            }
        }

        while(!Q.empty()) {
            int u = Q.front(); Q.pop();

            if(End[Fail[u]]) End[u] = 1;
            for(int i = 0; i < s; i++) {
                if(Next[u][i] == -1) {
                    Next[u][i] = Next[Fail[u]][i];
                } else {
                    Fail[Next[u][i]] = Next[Fail[u]][i];
                    Q.push(Next[u][i]);
                }
            }
        }
    }

    int Query() {
        memset(G, 0, sizeof(G));
        for(int i = 0; i < rear; i++) {
            for(int j = 0; j < s; j++) {
                if(End[Next[i][j]] == 0) {
                    G[i][Next[i][j]]++;
                }
            }
        }
        return rear;
    }
} AC;

struct BigInteger {
    int A[30];
    enum {MOD = 10000};
    BigInteger() {
        memset(A, 0, sizeof(A));
        A[0] = 1;
    }
    void set(int x) {
        memset(A, 0, sizeof(A));
        A[0] = 1;
        A[1] = x;
    }
    void print() {
        printf("%d", A[A[0]]);
        for (int i = A[0] - 1; i > 0; i--) {
            if (A[i] == 0) {
                printf("0000");
                continue;
            }
            for (int k = 10; k * A[i] < MOD; k *= 10) printf("0");
            printf("%d", A[i]);
        }
        printf("\n");
    }
    int& operator [] (int p) {
        return A[p];
    }
    const int& operator [] (int p) const {
        return A[p];
    }
    BigInteger operator + (const BigInteger& B) {
        BigInteger C;
        C[0] = max(A[0], B[0]);
        for (int i = 1; i <= C[0]; i++)
            C[i] += A[i] + B[i], C[i + 1] += C[i] / MOD, C[i] %= MOD;
        if (C[C[0] + 1] > 0) C[0]++;
        return C;
    }
    BigInteger operator * (const BigInteger& B) {
        BigInteger C;
        C[0] = A[0] + B[0];
        for (int i = 1; i <= A[0]; i++)
            for (int j = 1; j <= B[0]; j++) {
                C[i + j - 1] += A[i] * B[j], C[i + j] += C[i + j - 1] / MOD, C[i + j - 1] %= MOD;
            }
        if (C[C[0]] == 0) C[0]--;
        return C;
    }
};

char word[MX];
BigInteger dp[2][MX];

int main() {
    int n, m, p; //FIN;
    while(~scanf("%d%d%d", &n, &m, &p)) {
        memset(dp, 0, sizeof(dp));
        scanf("%s", word);
        AC.Init(word);

        for(int i = 1; i <= p; i++) {
            scanf("%s", word);
            AC.Add(word);
        }
        AC.Build();
        int s = AC.Query();

        int cur = 0, nxt = 1;
        dp[cur][0].set(1);
        for(int i = 1; i <= m; i++) {
            for(int j = 0; j < s; j++) {
                dp[nxt][j].set(0);
            }

            for(int j = 0; j < s; j++) {
                for(int k = 0; k < s; k++) {
                    if(G[j][k]) {
                        BigInteger temp;
                        temp.set(G[j][k]);
                        dp[nxt][k] = dp[nxt][k] + dp[cur][j] * temp;
                    }
                }
            }
            swap(cur, nxt);
        }

        BigInteger ans;
        for(int i = 0; i < s; i++) {
            ans = ans + dp[cur][i];
        }
        ans.print();
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python AC自动机是一个用于字符串匹配的算法,它可以高效地在一段文本中查找多个预定义的模式。它的实现可以使用多种库,其中包括ac自动机python和ahocorasick-python。 ac自动机python是一个对标准的ac自动机算法进行了完善和优化的实现,适用于主流的Python发行版,包括Python2和Python3。它提供了更准确的结果,并且可以通过pip进行安装,具体的安装方法可以参考官方文档或者使用pip install命令进行安装。 ahocorasick-python是另一个实现AC自动机的库,它也可以用于Python2和Python3。你可以通过官方网站或者GitHub源码获取更多关于该库的信息和安装指南。 对于AC自动机的使用,一个常见的例子是在一段包含m个字符的文章中查找n个单词出现的次数。要了解AC自动机,需要有关于模式树(字典树)Trie和KMP模式匹配算法的基础知识。AC自动机的算法包括三个步骤:构造一棵Trie树,构造失败指针和模式匹配过程。在构造好AC自动机后,可以使用它来快速地在文本中查找预定义的模式,并统计它们的出现次数。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [ahocorasick-python:AC自动机python的实现,并进行了优化。 主要修复了 查询不准确的问题](https://download.csdn.net/download/weixin_42122986/18825869)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Python实现多模匹配——AC自动机](https://blog.csdn.net/zichen_ziqi/article/details/104246446)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值