zoukankan      html  css  js  c++  java
  • HDU 2243 ( Trie图 矩阵构造幂和 )

    题意 :  长度不超过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。

    分析: 我们可以用Tire图跑矩阵快速幂的方法,去求长度为n不包含给定单词的词为sum; 所以想到求:长度为n包含给定单词的词 的算法就是用总的方案数-长度为n不包含给定单词的词的方案数为26^n-sum;  这题的难点是求长度不超过L的方案数,就是说我们需要求 26-sum1+26^2-sum2+26^3-sum3......26^n-sumn = (26+26^2+...26^n)-(sum1+sum2+...sumn); 我们显然不是遍历求; 考虑优先算法:

     假设原 Trie 图构建出来的状态矩阵为 A ,那么同样的我们需要构造一个幂和即 A1 + A2 + A+ ..... + A然后最后的答案便是 ∑AL(0, i)  ( i ∈ 1~矩阵长度 ) ,那怎么去构造这两个幂和呢?

     只要利用这个公式即可,用原矩阵 + 单位矩阵 + 零矩阵构造出新矩阵,最后右上角的矩阵便是幂和的矩阵

    需要注意的点:(1)在求(26+26^2+...26^n)的时候不能用等比数列公式去求,这样会有误差,可以用上面构造的矩阵的方法构造

    | 26,1 |

    |0 , 1 |  的跑矩阵快速幂

    (2 对于 2^64次方求模) 直接开unsigned long long 就好

    #include<string.h>
    #include<stdio.h>
    #include<iostream>
    #include<queue>
    #define ULL unsigned long long
    using namespace std;
    
    const int Max_Tot = 1e2 + 10;
    const int Letter  = 26;
    int maxn;///矩阵的大小
    char S[11];
    
    struct mat{ ULL m[111][111]; }unit, M;
    mat operator * (mat a, mat b){
        mat ret;
        for(int i=0; i<maxn; i++){
            for(int j=0; j<maxn; j++){
                ret.m[i][j] = (ULL)0;
                for(int k=0; k<maxn; k++){
                    ret.m[i][j] += a.m[i][k]*b.m[k][j];
                }
            }
        }
        return ret;
    }
    
    inline void init_unit() {
        for(int i=0; i<maxn; i++)
            unit.m[i][i] = 1;
    }
    
    mat pow_mat(mat a, long long n){
        mat ret = unit;
        while(n){
            if(n&1) ret = ret * a;
            a = a*a;
            n >>= 1;
        }
        return ret;
    }
    
    struct Aho{
        struct StateTable{
            int Next[Letter];
            int fail, flag;
        }Node[Max_Tot];
        int Size;
        queue<int> que;
    
        inline void init(){
            while(!que.empty()) que.pop();
            memset(Node[0].Next, 0, sizeof(Node[0].Next));
            Node[0].fail = Node[0].flag = 0;
            Size = 1;
        }
    
        inline void insert(char *s){
            int now = 0;
            for(int i=0; s[i]; i++){
                int idx = s[i] - 'a';
                if(!Node[now].Next[idx]){
                    memset(Node[Size].Next, 0, sizeof(Node[Size].Next));
                    Node[Size].fail = Node[Size].flag = 0;
                    Node[now].Next[idx] = Size++;
                }
                now = Node[now].Next[idx];
            }
            Node[now].flag = 1;
        }
    
        inline void BuildFail(){
            Node[0].fail = -1;
            for(int i=0; i<Letter; i++){
                if(Node[0].Next[i]){
                    Node[Node[0].Next[i]].fail = 0;
                    que.push(Node[0].Next[i]);
                }else Node[0].Next[i] = 0;///必定指向根节点
            }
            while(!que.empty()){
                int top = que.front(); que.pop();
                if(Node[Node[top].fail].flag) Node[top].flag = 1;
                for(int i=0; i<Letter; i++){
                    int &v = Node[top].Next[i];
                    if(v){
                        que.push(v);
                        Node[v].fail = Node[Node[top].fail].Next[i];
                    }else v = Node[Node[top].fail].Next[i];
                }
            }
        }
    
        inline void BuildMatrix(){
            for(int i=0; i<Size; i++)
                for(int j=0; j<Size; j++)
                    M.m[i][j] = 0;
            for(int i=0; i<Size; i++){
                for(int j=0; j<Letter; j++){
                    if(!Node[i].flag && !Node[ Node[i].Next[j] ].flag)
                        M.m[i][Node[i].Next[j]]++;
                }
            }
            maxn = Size;
        }
    }ac;
    
    ULL GetSum(long long num){
        mat ret;
        ret.m[0][0] = 26;
        ret.m[0][1] = 1;
        ret.m[1][0] = 0;
        ret.m[1][1] = 1;
        int tmp = maxn;
        maxn = 2;
        ret = pow_mat(ret, ++num);
        maxn = tmp;
        return ret.m[0][1]-1;
    }
    
    ULL GetElimination(long long num){
        mat tmp;
        for(int i=0; i<maxn; i++)///左上角 为 原矩阵
            for(int j=0; j<maxn; j++)
                tmp.m[i][j] = M.m[i][j];
    
        for(int i=0; i<maxn; i++)///右上角 为 单位矩阵
            for(int j=maxn; j<(maxn<<1); j++)
                tmp.m[i][j] = (i+maxn == j);
    
        for(int i=maxn; i<(maxn<<1); i++)///左下角 为 零矩阵
            for(int j=0; j<maxn; j++)
                tmp.m[i][j] = 0;
    
        for(int i=maxn; i<(maxn<<1); i++)///右下角 为 单位矩阵
            for(int j=maxn; j<(maxn<<1); j++)
                tmp.m[i][j] = (i==j);
    
        int Temp = maxn;
        maxn <<= 1;///先将原本矩阵的大小放大一倍进行快速幂运算,这个和我快速幂的写法有关
        tmp = pow_mat(tmp, ++num);
        ULL ret = (ULL)0;
        maxn = Temp;///再回复成原来大小
        for(int i=maxn; i<(maxn<<1); i++)///右上角的矩阵就是幂和了
            ret += tmp.m[0][i];
    
        return (--ret);///需要 -1
    }
    
    int main(void)
    {
        int n, m;
    
        while(~scanf("%d %d", &m, &n)){
            ac.init();
            for(int i=0; i<m; i++){
                scanf("%s", S);
                ac.insert(S);
            }
            ac.BuildFail();
            ac.BuildMatrix();
            init_unit();
            ULL Tot = GetSum((long long)n);///注意是传long long不然会爆int
            ULL Elimination = GetElimination((long long)n);
            cout<<Tot-Elimination<<endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    聊聊WS-Federation
    用双十一的故事串起碎片的网络协议(上)
    责任链模式的使用-Netty ChannelPipeline和Mina IoFilterChain分析
    最小化局部边际的合并聚类算法(中篇)
    最小化局部边际的合并聚类算法(上篇)
    UVaLive 7371 Triangle (水题,判矩形)
    UVaLive 7372 Excellence (水题,贪心)
    POJ 3312 Mahershalalhashbaz, Nebuchadnezzar, and Billy Bob Benjamin Go to the Regionals (水题,贪心)
    UVa 1252 Twenty Questions (状压DP+记忆化搜索)
    UVa 10817 Headmaster's Headache (状压DP+记忆化搜索)
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/11615477.html
Copyright © 2011-2022 走看看