• HDU-2243-考研路茫茫——单词情结(AC自动机, 矩阵快速幂)


    链接:

    https://vjudge.net/problem/HDU-2243

    题意:

    背单词,始终是复习英语的重要环节。在荒废了3年大学生涯后,Lele也终于要开始背单词了。
    一天,Lele在某本单词书上看到了一个根据词根来背单词的方法。比如"ab",放在单词前一般表示"相反,变坏,离去"等。

    于是Lele想,如果背了N个词根,那这些词根到底会不会在单词里出现呢。更确切的描述是:长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义。

    比如一共有2个词根 aa 和 ab ,则可能存在104个长度不超过3的单词,分别为
    (2个) aa,ab,
    (26个)aaa,aab,aac...aaz,
    (26个)aba,abb,abc...abz,
    (25个)baa,caa,daa...zaa,
    (25个)bab,cab,dab...zab。

    这个只是很小的情况。而对于其他复杂点的情况,Lele实在是数不出来了,现在就请你帮帮他。

    思路:

    这两天的AC自动机刷新了认知, 矩阵还能这么用.
    考虑每次可以走任意方向, 在考虑不能走出现模板串的总次数, 就是所有次数-不走次数, 等于最少走一次的次数.
    对于不走的次数, 就和poj-2778一样, 而所有次数, 考虑s = 261+262+..+26^m.
    有s+1 = 1+261+..+26m.另f(n) = s+1, 则f(n) = 26*f(n-1)+1. 得出矩阵
    f(n) = | 26 1 | * |f(n-1)|
    1 | 0 1 | * | 1 |
    两次矩阵快速幂.

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    //#include <memory.h>
    #include <queue>
    #include <set>
    #include <map>
    #include <algorithm>
    #include <math.h>
    #include <stack>
    #include <string>
    #include <assert.h>
    #include <iomanip>
    #include <iostream>
    #include <sstream>
    #define MINF 0x3f3f3f3f
    using namespace std;
    typedef unsigned long long LL;
    const LL MAXN = 2e6+10;
    
    struct AcTree
    {
        int Next[26];
        int fail;
        int end;
        int ok;
        void Init()
        {
            memset(Next, 0, sizeof(Next));
            end = 0;
            fail = 0;
            ok = 1;
        }
    }tree[MAXN];
    struct Martix
    {
        LL mar[110][110];
        int n;
        void Inin(const int *key, int len, const int *value)
        {
            memset(mar, 0, sizeof(mar));
            n = len;
            for (int i = 1;i <= n;i++)
            {
                for (int j = 0;j < 26;j++)
                {
                    int node = tree[key[i]].Next[j];
                    if (tree[node].ok == 0)
                        continue;
                    mar[i][value[node]]++;
    //                cout << key[i] << ' ' << node << endl;
                }
            }
            n++;
            for (int i = 1;i <= n;i++)
                mar[i][n] = 1;
        }
        Martix& operator * (const Martix& that)
        {
            LL tmp[110][110];
            for (int i = 1;i <= n;i++)
            {
                for (int j = 1;j <= n;j++)
                {
                    LL tmpval = 0;
                    for (int k = 1;k <= n;k++)
                        tmpval = tmpval+this->mar[i][k]*that.mar[k][j];
                    tmp[i][j] = tmpval;
                }
            }
            for (int i = 1;i <= n;i++)
            {
                for (int j = 1;j <= n;j++)
                    this->mar[i][j] = tmp[i][j];
            }
            return *this;
        }
    }Mar;
    char s[MAXN];
    int Key[110], Value[110*110];
    LL n, m, cnt;
    
    void Insert(char *s)
    {
        int len = strlen(s);
        int pos = 0;
        for (int i = 0;i < len;i++)
    
        {
            if (tree[pos].Next[s[i]-'a'] == 0)
            {
                tree[pos].Next[s[i]-'a'] = ++cnt;
                tree[cnt].Init();
            }
            pos = tree[pos].Next[s[i]-'a'];
        }
        tree[pos].end = 1;
        tree[pos].ok = 0;
    }
    
    void BuildAC()
    {
        queue<int> que;
        for (int i = 0;i < 26;i++)
        {
            if (tree[0].Next[i] != 0)
                tree[tree[0].Next[i]].fail = 0, que.push(tree[0].Next[i]);
    
        }
        while (!que.empty())
        {
            int u = que.front();
            que.pop();
            if (tree[tree[u].fail].ok == 0)
                tree[u].ok = 0;
            for (int i = 0;i < 26;i++)
            {
                if (tree[u].Next[i] != 0)
                {
                    tree[tree[u].Next[i]].fail = tree[tree[u].fail].Next[i];
                    que.push(tree[u].Next[i]);
                }
                else
                    tree[u].Next[i] = tree[tree[u].fail].Next[i];
            }
        }
    }
    
    Martix QuickMartixMi(Martix a, LL b)
    {
        b--;
        Martix res = a;
        while (b)
        {
            if (b&1)
                res*a;
            a*a;
            b >>= 1;
        }
        return res;
    }
    
    int main()
    {
        while(~scanf("%d%d", &m, &n))
        {
            cnt = 0;
            tree[0].Init();
            for (int i = 1; i <= m; i++)
            {
                scanf("%s", s);
                Insert(s);
            }
            BuildAC();
            int tmp = 0;
            for (int i = 0;i <= cnt;i++)
            {
                if (tree[i].ok)
                    Key[++tmp] = i, Value[i] = tmp;
            }
            Mar.Inin(Key, tmp, Value);
            Martix res = QuickMartixMi(Mar, n);
            LL ans = 0;
            for (int i = 1;i <= res.n;i++)
                ans += res.mar[1][i];
            ans--;//不存在
            Martix Sum;
            Sum.n = 2;
            memset(Sum.mar, 0, sizeof(Sum.mar));
            Sum.mar[1][1] = 26;
            Sum.mar[1][2] = Sum.mar[2][2] = 1;
            Sum = QuickMartixMi(Sum, n);
            cout << Sum.mar[1][1]+Sum.mar[1][2]-1-ans << endl;
        }
    
        return 0;
    }
    
  • 相关阅读:
    “是懒人造就了方法”——读后感
    多态性动手动脑
    数组问题随笔
    String java问题随笔
    java问题总结
    java问题随笔
    java一些问题的解答
    利用参数的值得返回来求和
    是懒人造就了方法——读后感
    大道至简读后感——JAVA伪代码
  • 原文地址:https://www.cnblogs.com/YDDDD/p/11638717.html
Copyright © 2020-2023  润新知