zoukankan      html  css  js  c++  java
  • Kuangbin带你飞 AC自动机

    模板:

    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int fail[MAXNNODE],last[MAXNNODE];
        bool symbol[MAXNNODE];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));symbol[0] = false;}
        int idx(char c)
        {
            return c - 'a';
        }
    
        void insert(char * s)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    symbol[sz] = false;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            symbol[u] = true;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        void get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                if (symbol[fail[r]]) symbol[r] = true;
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
               // printf("%d
    ",val[j]);
               // cnt[val[j]]++;
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
            symbol[0] = false;
        }
    
        Matrix build_mat()
        {
            Matrix ret = Matrix(sz + 1);
            for (int i = 0 ; i < sz ; i++)
                for (int j = 0 ; j < SIGMA_SIZE ; j++)
                    if (symbol[i] == false && !symbol[ch[i][j]])
                        ret.mat[i][ch[i][j]]++;
            for (int i = 0 ; i <= sz ; i++)
                ret.mat[i][sz] = 1;
            return ret;
        }
    }src;

    HDU 2222 Keywords Search

    找出主串中有多少个模式串出现

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    int ans;
    const int MAXNNODE = 500010;
    const int SIGMA_SIZE = 26;
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int cnt[MAXNNODE];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));}
        int idx(char c) {return c - 'a';}
    
        void insert(char * s,int v)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            cnt[u]++;
            val[u] = v;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        int fail[MAXNNODE],last[MAXNNODE];
        int get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
                ans += cnt[j];
                cnt[j] = 0;
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
            memset(cnt,false,sizeof(cnt));
        }
    }src;
    int N;
    char input[60];
    char tag[1000005];
    int main()
    {
        //freopen("sample.txt","r",stdin);
        int T;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d",&N);
            gets(input);
            src.init();
            ans = 0;
            for (int i = 0 ; i < N; i++)
            {
                gets(input);
                src.insert(input,i + 1);
            }
            scanf("%s",tag);
            src.get_fail();
            src.Find(tag);
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    HDU 2896 病毒侵袭

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXNNODE = 100010;
    const int SIGMA_SIZE = 130;
    vector<int>ans;
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));}
        int idx(char c) {return c;}
    
        void insert(char * s,int v)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
    
            val[u] = v;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        int fail[MAXNNODE],last[MAXNNODE];
        void get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
                ans.push_back(val[j]);
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
            //memset(cnt,false,sizeof(cnt));
        }
    }src;
    char tmp[210];
    int N,M;
    char tag[10010];
    int main()
    {
        //freopen("sample.txt","r",stdin);
        while (scanf("%d",&N) != EOF)
        {
            src.init();
            for (int i = 1; i <= N; i++)
            {
                scanf("%s",tmp);
                src.insert(tmp,i);
            }
            src.get_fail();
            scanf("%d",&M);
            int ret = 0;
            for (int i = 1; i <= M; i++)
            {
                ans.clear();
                scanf("%s",tag);
                src.Find(tag);
                if (ans.size() == 0) continue;
                ret++;
                printf("web %d:",i);
                    sort(ans.begin(),ans.end());
                int k = unique(ans.begin(),ans.end()) - ans.begin();
                for (int i = 0 ; i < k ; i++)
                    printf(" %d",ans[i]);
                putchar('
    ');
            }
            printf("total: %d
    ",ret);
        }
        return 0;
    }
    View Code

    HDU 3065 病毒侵袭持续中

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXNNODE = 50010;
    const int SIGMA_SIZE = 128;
    int cnt[MAXNNODE];
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int fail[MAXNNODE],last[MAXNNODE];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));}
        int idx(char c) {return c - 'A';}
    
        void insert(char * s,int v)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            val[u] = v;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        void get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
               // printf("%d
    ",val[j]);
                cnt[val[j]]++;
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
        }
    }src;
    char input[1010][60];
    char word[2000005];
    int N;
    int main()
    {
        while (scanf("%d",&N) != EOF)
        {
            memset(cnt,0,sizeof(cnt));
            src.init();
            for (int i = 1 ; i <= N ; i++)
            {
                scanf("%s",input[i]);
                src.insert(input[i],i);
            }
            src.get_fail();
            scanf("%s",word);
            src.Find(word);
            for (int i = 1 ; i <= N ; i++)
            {
                if (cnt[i])
                    printf("%s: %d
    ",input[i],cnt[i]);
            }
        }
        return 0;
    }
    View Code

    ZOJ 3430 Detect the Virus

    题意:给出n个编码后的模板串,然后有M次询问,每次询问输入一个编码后的文本串,问在编码前,有多少个模板串在文本串中出现过。

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int SIGMA_SIZE = 256;
    const int MAXNNODE = 60010;
    vector<int>ret;
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int fail[MAXNNODE],last[MAXNNODE];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));}
       // int idx(char c) {return c;}
    
        void insert(int * s,int n,int v)
        {
            int u = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = s[i];
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            val[u] = v;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        void get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
               // printf("%d
    ",val[j]);
                ret.push_back(val[j]);
                print(last[j]);
            }
        }
    
        void Find(int * T,int n)
        {
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = T[i];
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
        }
    }src;
    
    int getid(char ch) {
        if (isupper(ch)) return ch - 'A';
        if (islower(ch)) return ch - 'a' + 26;
        if (isdigit(ch)) return ch - '0' + 52;
        if (ch == '+') return 62;
        return 63;
    }
    
    int str[30010];
    char word[30010];
    int bit[30010 * 10];
    int decode(char * s) {
        int top = 0,res[10];
        int len = strlen(s);
        for (int i = 0 ; i < len ; i++) {
            if (s[i] != '=') {
                int idx = getid(s[i]);
                for (int j = 5 ; j >= 0 ; j--) {
                    res[j] = idx & 1;
                    idx >>= 1;
                }
                for (int j = 0 ; j < 6 ; j++) {
                    bit[top++] = res[j];
                }
            }
            else  top -= 2;
        }
        int x = 0,tot = 0;
        for (int i = 0 ; i < top ;) {
            x = 0;
            for (int j = 0 ; j < 8 ; j++)
                x = x * 2 + bit[i++];
            str[tot++] = x;
        }
        return tot;
    }
    
    int main() {
        int N,M;
        while (scanf("%d",&N) != EOF) {
            src.init();
            for (int i = 1 ; i <= N ; i++) {
                scanf("%s",word);
                int length = decode(word);
                src.insert(str,length,i);
            }
            src.get_fail();
            scanf("%d",&M);
            while (M--) {
                ret.clear();
                scanf("%s",word);
                int length = decode(word);
                src.Find(str,length);
                sort(ret.begin(),ret.end());
                int cnt = unique(ret.begin(),ret.end()) - ret.begin();
                printf("%d
    ",cnt);
            }
            puts("");
        }
        return 0;
    }
    View Code

    POJ 2778 DNA Sequence

    题意:有m种DNA序列是有疾病的,问有多少种长度为n的DNA序列不包含任何一种有疾病的DNA序列。(仅含A,T,C,G四个字符)

    复制一下别人的题解

    这个和矩阵有什么关系呢???
    •上图是例子{“ACG”,”C”},构建trie图后如图所示,从每个结点出发都有4条边(A,T,C,G)
    •从状态0出发走一步有4种走法:
      –走A到状态1(安全);
      –走C到状态4(危险);
      –走T到状态0(安全);
      –走G到状态0(安全);
    •所以当n=1时,答案就是3
    •当n=2时,就是从状态0出发走2步,就形成一个长度为2的字符串,只要路径上没有经过危险结点,有几种走法,那么答案就是几种。依此类推走n步就形成长度为n的字符串。
    •建立trie图的邻接矩阵M:

    2 1 0 0 1

    2 1 1 0 0

    1 1 0 1 1

    2 1 0 0 1

    2 1 0 0 1

    M[i,j]表示从结点i到j只走一步有几种走法。

    那么M的n次幂就表示从结点i到j走n步有几种走法。

    注意:危险结点要去掉,也就是去掉危险结点的行和列。结点3和4是单词结尾所以危险,结点2的fail指针指向4,当匹配”AC”时也就匹配了”C”,所以2也是危险的。

    矩阵变成M:

    2 1

    2 1

    计算M[][]的n次幂,然后 Σ(M[0,i]) mod 100000 就是答案。

    由于n很大,可以使用二分来计算矩阵的幂

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXNNODE = 150;
    const int SIGMA_SIZE = 4;
    const LL MOD = 100000;
    struct Matrix {
        LL mat[MAXNNODE][MAXNNODE];
        int n;
        Matrix(){}
        Matrix(int sz) {
            n = sz;
            for (int i = 0 ; i < n ; i++)
                for (int j = 0 ; j < n ; j++) mat[i][j] = 0;
        }
    
        Matrix operator * (const Matrix &b) const{
            Matrix ret = Matrix(n);
            for (int i = 0 ; i < n ; i++)
                for (int j = 0 ; j < n ; j++)
                        for (int k = 0 ; k < n ; k++)
                            ret.mat[i][j] = (ret.mat[i][j] + mat[i][k] * b.mat[k][j]) % MOD;
            return ret;
        }
    };
    
    LL pow_mod(LL x,int cnt) {
        LL ret = 1;
        while (cnt) {
            if (cnt & 1) ret = ret * x;
            x = x * x % MOD;
            cnt >>= 1;
        }
        return ret;
    }
    
    Matrix mat_pow(Matrix in,LL cnt) {
        Matrix ret = Matrix(in.n);
        Matrix x = in;
        for (int i = 0 ; i < ret.n ; i++)   ret.mat[i][i] = 1;
        while (cnt) {
            if (cnt & 1LL) ret = ret * x;
            x = x * x;
            cnt >>= 1LL;
        }
        return ret;
    }
    
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int fail[MAXNNODE],last[MAXNNODE];
        bool symbol[MAXNNODE];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));symbol[0] = false;}
        int idx(char c)
        {
            if (c == 'A') return 0;
            if (c == 'T') return 1;
            if (c == 'C') return 2;
            return 3;
        }
    
        void insert(char * s)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    symbol[sz] = false;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            symbol[u] = true;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        void get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                if (symbol[fail[r]]) symbol[r] = true;
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
               // printf("%d
    ",val[j]);
               // cnt[val[j]]++;
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
            symbol[0] = false;
        }
    
        Matrix build_mat()
        {
            Matrix ret = Matrix(sz);
            for (int i = 0 ; i < sz ; i++)
                for (int j = 0 ; j < SIGMA_SIZE ; j++)
                    if (symbol[i] == false && !symbol[ch[i][j]])
                        ret.mat[i][ch[i][j]]++;
            return ret;
        }
    }src;
    
    
    int main() {
        LL M,N;
        char tmp[20];
        while (scanf("%I64d%I64d",&M,&N) != EOF) {
            src.init();
            for (int i = 0 ; i < M ; i++) {
                scanf("%s",tmp);
                src.insert(tmp);
            }
            src.get_fail();
            Matrix cur = src.build_mat();
           /* for (int i = 0 ; i < cur.n ; i++){
                for (int j = 0 ; j < cur.n ; j++)
                    printf("%I64d ",cur.mat[i][j]);
                puts("");
            }*/
           // Matrix ret = cur * cur * cur;
            Matrix ret = mat_pow(cur,N);
           /* for (int i = 0 ; i < cur.n ; i++){
                for (int j = 0 ; j < cur.n ; j++)
                    printf("%I64d ",ret.mat[i][j]);
                puts("");
            }*/
            LL ans = 0;
            for (int i = 0 ; i < src.sz ; i++)
                ans = (ans + ret.mat[0][i]) % MOD;
            printf("%I64d
    ",ans);
        }
        return 0;
    }
    View Code

    HDU 2243 考研路茫茫――单词情结

    这题的意思是,给你n个长度不超过5的字符串,求有多少个长度为至少为L的字符串,里面至少包含n个字符串中的一个。

    这题和求DNA片段的差不多啦,只不过L的条件有点变化。

    POJ2778 是求长度为n,不包含模式串。

    假设矩阵A里储存着字符间的可行转移,那么A^L就代表了长度为L的不包含n个字符串中任何一个的个数。

    最终的答案就是26^1+26^2+......+26^L减去A^1+A^2+....+A^L

    矩阵A可以用ac自动机维护一个跳转表得到。接下来就是考虑如何快速的求得A^1+A^2+....+A^L了。

    根据矩阵的性质

    |A  ,  1|                 |A^n , 1+A^1+A^2+....+A^(n-1)| 

    |0  ,  1| 的n次方等于|0     ,                                       1|      

    利用POJ 2778 的方式构建A

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ULL unsigned long long
    #define LL unsigned long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXNNODE = 150;
    const int SIGMA_SIZE = 26;
    const LL MOD = 100000;
    struct Matrix {
        ULL mat[MAXNNODE][MAXNNODE];
        int n;
        Matrix(){}
        Matrix(int sz) {
            n = sz;
            for (int i = 0 ; i < n ; i++)
                for (int j = 0 ; j < n ; j++) mat[i][j] = 0;
        }
    
        Matrix operator * (const Matrix &b) const{
            Matrix ret = Matrix(n);
            for (int i = 0 ; i < n ; i++)
                for (int j = 0 ; j < n ; j++)
                        for (int k = 0 ; k < n ; k++)
                            ret.mat[i][j] = (ret.mat[i][j] + mat[i][k] * b.mat[k][j]);
            return ret;
        }
    };
    
    LL pow_mod(LL x,int cnt) {
        LL ret = 1;
        while (cnt) {
            if (cnt & 1) ret = ret * x;
            x = x * x % MOD;
            cnt >>= 1;
        }
        return ret;
    }
    
    Matrix mat_pow(Matrix in,LL cnt) {
        Matrix ret = Matrix(in.n);
        Matrix x = in;
        for (int i = 0 ; i < ret.n ; i++)   ret.mat[i][i] = 1;
        while (cnt) {
            if (cnt & 1LL) ret = ret * x;
            x = x * x;
            cnt >>= 1LL;
        }
        return ret;
    }
    
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int fail[MAXNNODE],last[MAXNNODE];
        bool symbol[MAXNNODE];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));symbol[0] = false;}
        int idx(char c)
        {
            return c - 'a';
        }
    
        void insert(char * s)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    symbol[sz] = false;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            symbol[u] = true;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        void get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                if (symbol[fail[r]]) symbol[r] = true;
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
               // printf("%d
    ",val[j]);
               // cnt[val[j]]++;
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
            symbol[0] = false;
        }
    
        Matrix build_mat()
        {
            Matrix ret = Matrix(sz + 1);
            for (int i = 0 ; i < sz ; i++)
                for (int j = 0 ; j < SIGMA_SIZE ; j++)
                    if (symbol[i] == false && !symbol[ch[i][j]])
                        ret.mat[i][ch[i][j]]++;
            for (int i = 0 ; i <= sz ; i++)
                ret.mat[i][sz] = 1;
            return ret;
        }
    }src;
    
    
    int main() {
        LL M,N;
        char tmp[20];
        while (scanf("%I64d%I64d",&M,&N) != EOF) {
            src.init();
            for (int i = 0 ; i < M ; i++) {
                scanf("%s",tmp);
                src.insert(tmp);
            }
            src.get_fail();
            Matrix cur = src.build_mat();
           /* for (int i = 0 ; i < cur.n ; i++){
                for (int j = 0 ; j < cur.n ; j++)
                    printf("%I64d ",cur.mat[i][j]);
                puts("");
            }*/
           // Matrix ret = cur * cur * cur;
            Matrix ret = mat_pow(cur,N);
           /* for (int i = 0 ; i < cur.n ; i++){
                for (int j = 0 ; j < cur.n ; j++)
                    printf("%I64d ",ret.mat[i][j]);
                puts("");
            }*/
            ULL ans = 0;
            for (int i = 0 ; i <= src.sz ; i++)
                ans = (ans + ret.mat[0][i]);
            ans--;
    
            Matrix t = Matrix(2);
            t.mat[0][0] = 26;
            t.mat[1][0] = t.mat[1][1] = 1;
            t = mat_pow(t,N);
            ULL res = t.mat[0][0] + t.mat[1][0];
            // << res << endl;
            res--;
            printf("%I64u
    ",res - ans);
        }
        return 0;
    }
    View Code

    POJ 1625 Censored!

    题意:给出包含n个可见字符的字符集,以下所提字符串均由该字符集中的字符构成。给出p个长度不超过10的字符串,求长为m且不包含上述p个字符串的字符串有多少个。

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    map<char,int>mp;
    struct Matrix
    {
        int mat[110][110];
        int n;
        Matrix(){}
        Matrix(int sz)
        {
            n = sz;
            for (int i = 0 ; i < n ; i++)
                for (int j = 0 ; j < n ; j++) mat[i][j] = 0;
        }
    }mt;
    
    const int numlen = 104;
    const int MAXNNODE = 130 * 200;
    const int SIGMA_SIZE = 130;
    int N,M,P,cas;
    struct bign {
        int len, s[numlen];
        bign() {
            memset(s, 0, sizeof(s));
            len = 1;
        }
        bign(int num) { *this = num; }
        bign(const char *num) { *this = num; }
        bign operator = (const int num) {
            char s[numlen];
            sprintf(s, "%d", num);
            *this = s;
            return *this;
        }
        bign operator = (const char *num) {
            len = strlen(num);
            while(len > 1 && num[0] == '0') num++, len--;
            for(int i = 0;i < len; i++) s[i] = num[len-i-1] - '0';
            return *this;
        }
    
        void deal() {
            while(len > 1 && !s[len-1]) len--;
        }
    
        bign operator + (const bign &a) const {
            bign ret;
            ret.len = 0;
            int top = max(len, a.len) , add = 0;
            for(int i = 0;add || i < top; i++) {
                int now = add;
                if(i < len) now += s[i];
                if(i < a.len)   now += a.s[i];
                ret.s[ret.len++] = now%10;
                add = now/10;
            }
            return ret;
        }
        bign operator - (const bign &a) const {
            bign ret;
            ret.len = 0;
            int cal = 0;
            for(int i = 0;i < len; i++) {
                int now = s[i] - cal;
                if(i < a.len)   now -= a.s[i];
                if(now >= 0)    cal = 0;
                else {
                    cal = 1; now += 10;
                }
                ret.s[ret.len++] = now;
            }
            ret.deal();
            return ret;
        }
        bign operator * (const bign &a) const {
            bign ret;
            ret.len = len + a.len;
            for(int i = 0;i < len; i++) {
                for(int j = 0;j < a.len; j++)
                    ret.s[i+j] += s[i]*a.s[j];
            }
            for(int i = 0;i < ret.len; i++) {
                ret.s[i+1] += ret.s[i]/10;
                ret.s[i] %= 10;
            }
            ret.deal();
            return ret;
        }
    
        bign operator * (const int num) {
    //        printf("num = %d
    ", num);
            bign ret;
            ret.len = 0;
            int bb = 0;
            for(int i = 0;i < len; i++) {
                int now = bb + s[i]*num;
                ret.s[ret.len++] = now%10;
                bb = now/10;
            }
            while(bb) {
                ret.s[ret.len++] = bb % 10;
                bb /= 10;
            }
            ret.deal();
            return ret;
        }
    
        bign operator / (const bign &a) const {
            bign ret, cur = 0;
            ret.len = len;
            for(int i = len-1;i >= 0; i--) {
                cur = cur*10;
                cur.s[0] = s[i];
                while(cur >= a) {
                    cur -= a;
                    ret.s[i]++;
                }
            }
            ret.deal();
            return ret;
        }
    
        bign operator % (const bign &a) const {
            bign b = *this / a;
            return *this - b*a;
        }
    
        bign operator += (const bign &a) { *this = *this + a; return *this; }
        bign operator -= (const bign &a) { *this = *this - a; return *this; }
        bign operator *= (const bign &a) { *this = *this * a; return *this; }
        bign operator /= (const bign &a) { *this = *this / a; return *this; }
        bign operator %= (const bign &a) { *this = *this % a; return *this; }
    
        bool operator < (const bign &a) const {
            if(len != a.len)    return len < a.len;
            for(int i = len-1;i >= 0; i--) if(s[i] != a.s[i])
                return s[i] < a.s[i];
            return false;
        }
        bool operator > (const bign &a) const  { return a < *this; }
        bool operator <= (const bign &a) const { return !(*this > a); }
        bool operator >= (const bign &a) const { return !(*this < a); }
        bool operator == (const bign &a) const { return !(*this > a || *this < a); }
        bool operator != (const bign &a) const { return *this > a || *this < a; }
    
        string str() const {
            string ret = "";
            for(int i = 0;i < len; i++) ret = char(s[i] + '0') + ret;
            return ret;
        }
    };
    istream& operator >> (istream &in, bign &x) {
        string s;
        in >> s;
        x = s.c_str();
        return in;
    }
    ostream& operator << (ostream &out, const bign &x) {
        out << x.str();
        return out;
    }
    
    bign dp[2][110];
    
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int fail[MAXNNODE],last[MAXNNODE];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));}
        int idx(char c) {return mp[c];}
    
        void insert(char * s,int v)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            val[u] = v;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        void get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                val[r] |= val[fail[r]];
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
               // printf("%d
    ",val[j]);
                //cnt[val[j]]++;
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
        }
    
        Matrix build_mat()
        {
            Matrix ret = Matrix(sz);
            for (int i = 0 ; i < sz ; i++)
            {
                for (int j = 0 ; j < N ; j++)
                    if (val[ch[i][j]] == false)
                        ret.mat[i][ch[i][j]]++;
            }
            return ret;
        }
    
    
        void slove()
        {
            int cur = 0;
            dp[cur][0] = 1;
            for (int i = 1 ; i < sz ; i++)
                dp[cur][i] = 0;
            for (int i = 0 ; i < M ; i++)
            {
                cur ^= 1;
                for (int j = 0 ; j < sz ; j++) dp[cur][j] = 0;
                for (int j = 0 ; j < sz ; j++)
                {
                    for (int k = 0 ; k < sz ; k++)
                    if (mt.mat[j][k] > 0)
                    dp[cur][k] = dp[cur][k] + dp[cur ^ 1][j] * mt.mat[j][k];
                }
            }
            bign ret = "0";
            for (int i = 0 ; i < sz ; i++)
                ret = ret + dp[cur][i];
            cout << ret << endl;
        }
    }src;
    char str[100];
    int main()
    {
       // freopen("sample.txt","r",stdin);
        while (scanf("%d%d%d",&N,&M,&P) != EOF)
        {
            mp.clear();
            gets(str);
            cas = 0;
            gets(str);
            int len = strlen(str);
            for (int i = 0 ; i < len ; i++)
                mp[str[i]] = cas++;
            src.init();
            for (int i = 0 ; i < P; i++)
            {
                gets(str);
                src.insert(str,1);
            }
            src.get_fail();
            mt = src.build_mat();
            src.slove();
        }
        return 0;
    }
    View Code

    HDU 2825 Wireless Password

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXNNODE = 110;
    const int SIGMA_SIZE = 26;
    const int MOD = 20090717;
    int N,M,K;
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int dp[2][MAXNNODE][1 << 10];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));}
        int idx(char c) {return c - 'a';}
    
        void insert(char * s,int v)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            val[u] = v;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        int fail[MAXNNODE],last[MAXNNODE];
        void get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                val[r] |= val[fail[r]];
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                  //  val[u] |= val[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
    
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
           // memset(cnt,false,sizeof(cnt));
        }
    
        int calcu(int n,int sta,int num)
        {
            memset(dp[0],0,sizeof(dp[0]));
            int cur = 0,nxt;
            dp[0][0][0] = 1;
            while (n--)
            {
                nxt = 1 - cur;
                memset(dp[nxt],0,sizeof(dp[nxt]));
                for (int i = 0 ; i < sz ; i++)
                    for (int j = 0 ; j < sta ; j++)
                {
                    if (dp[cur][i][j] == 0) continue;
                    for (int k = 0 ; k < SIGMA_SIZE ; k++)
                    {
                        int tmp = ch[i][k];
                        int nextsta = (j | (val[tmp]));
                        dp[nxt][tmp][nextsta] = (dp[nxt][tmp][nextsta] + dp[cur][i][j]) % MOD;
                    }
                }
                cur = nxt;
            }
            int ret = 0;
            for (int j = 0 ; j < sta ; j++)
            {
                int cnt = 0;
                for (int i = 0 ; i < N; i++)
                    if (j & (1 << i)) cnt++;
                if (cnt >= K)
                {
                    for (int t = 0 ; t < sz ; t++)
                        ret = (ret + dp[cur][t][j]) % MOD;
                }
            }
            return ret;
        }
    }src;
    int main()
    {
        //freopen("sample.txt","r",stdin);
        while (scanf("%d%d%d",&N,&M,&K) != EOF)
        {
            if (N == 0 && M == 0 && K == 0) break;
            src.init();
            for (int i = 0 ; i < M; i++)
            {
                char tmp[20];
                scanf("%s",tmp);
                src.insert(tmp,1 << i);
            }
            src.get_fail();
            printf("%d
    ",src.calcu(N,1 << M,K));
        }
        return 0;
    }
    View Code

    HDU 2296 Ring

    题目:给出m个模式串,每个串有一定的分值,构造一个长度不超过n的串,使得分值最大,输出长度最小,字典序最小的串

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXNNODE = 1110;
    const int SIGMA_SIZE = 26;
    const int INF = 0x3f3f3f3f;
    int N,M;
    int h[MAXNNODE];
    char res[60][MAXNNODE][60];
    
    bool cmp(char * s,char * t)
    {
        int len1 = strlen(s);
        int len2 = strlen(t);
        if (len1 != len2) return len1 < len2;
        return strcmp(s,t) < 0;
    }
    
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int fail[MAXNNODE],last[MAXNNODE];
        int sz;
        LL dp[60][MAXNNODE];
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));}
        int idx(char c) {return c - 'a';}
    
        void insert(char * s,int v)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            val[u] = v;//最后的叶子节点给与信息v
           // printf("%d %d
    ",u,v);
        }
    
        //建立字典树
    
        void get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
               // printf("%d
    ",val[j]);
               // cnt[val[j]]++;
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
        }
        
        void calcu()
        {
            for (int i = 0 ; i <= N ; i++)
                for (int j = 0 ; j < sz ; j++) dp[i][j] = -INF;
            dp[0][0] = 0;
            strcpy(res[0][0],"");
            char ret[60];
            strcpy(ret,"");
            int MAX = 0;
            char tmp[60];
            for (int i = 0 ; i < N ; i++)
            {
                for (int j = 0 ; j < sz ; j++)
                {
                    if (dp[i][j] < 0) continue;
                    strcpy(tmp,res[i][j]);
                    int len = strlen(tmp);
                    for (int k = 0 ; k < SIGMA_SIZE ; k++)
                    {
                        int nxt = ch[j][k];
                        tmp[len] = k + 'a';
                        tmp[len + 1] = '';
                        //len++;
                        int value = dp[i][j];
                        if (val[nxt]) value += h[val[nxt]];
                    //    if (value != 0) printf("%s %d
    ",tmp);
                        if (dp[i + 1][nxt] < value || (dp[i + 1][nxt] == value && cmp(tmp,res[i + 1][nxt])))
                        {
                            dp[i + 1][nxt] = value;
                            strcpy(res[i + 1][nxt],tmp);
                            if (value > MAX || (value == MAX && cmp(tmp,ret)))
                            {
                                MAX = value;
                                strcpy(ret,tmp);
                            }
                        }
                    }
                }
            }
        //    printf("%d
    ",MAX);
            printf("%s
    ",ret);
        }
    }src;
    
    int main()
    {
        int T;
        char buf[60];
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d%d",&N,&M);
            src.init();
            for (int i = 0 ; i < M ; i++)
            {
                scanf("%s",buf);
                src.insert(buf,i + 1);
            }
            for (int i = 1 ; i <= M ; i++) scanf("%d",&h[i]);
            src.get_fail();
            src.calcu();
        }
        return 0;
    }
    View Code

    HDU 2457 DNA repair

    题目:给出一些不合法的模式DNA串,给出一个原串,问最少需要修改多少个字符,使得原串中不包含非法串

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXNNODE = 1100;
    const int SIGMA_SIZE = 4;
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int fail[MAXNNODE],last[MAXNNODE];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));}
        int idx(char c)
        {
            if (c == 'A') return 0;
            if (c == 'G') return 1;
            if (c == 'C') return 2;
            if (c == 'T') return 3;
        }
    
        void insert(char * s,int v)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            val[u] = v;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        void get_fail()
        {
            queue<int>q;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                if (val[fail[r]])
                    val[r] = true;
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
               // printf("%d
    ",val[j]);
                //cnt[val[j]]++;
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
        }
    }src;
    int dp[1110][1100];
    int N;
    char str[1010];
    int main()
    {
       // freopen("sample.txt","r",stdin);
        int kase = 1;
        while (scanf("%d",&N) != EOF)
        {
            if (N == 0) break;
            src.init();
            memset(dp,-1,sizeof(dp));
            for (int i = 0 ; i < N; i++)
            {
                scanf("%s",str);
                src.insert(str,1);
            }
            src.get_fail();
            scanf("%s",str + 1);
            int len = strlen(str + 1);
            dp[0][0] = 0;
            for (int i = 0 ; i < len ; i++)
            {
                for (int j = 0 ; j < src.sz ; j++)
                {
                    if (dp[i][j] == -1) continue;
                    int idx = src.idx(str[i + 1]);
                    for (int k = 0 ; k < 4 ; k++)
                    {
                        int add = 0;
                        if (k != idx)  add = 1;
                        if (src.val[src.ch[j][k]]) continue;
                        if (dp[i + 1][src.ch[j][k]] == -1) dp[i + 1][src.ch[j][k]] = dp[i][j] + add;
                        else dp[i + 1][src.ch[j][k]] = min(dp[i + 1][src.ch[j][k]],dp[i][j] + add);
                    }
                }
            }
            int ret = INT_MAX;
            for (int i = 0 ; i < src.sz ; i++)
            {
                if (dp[len][i] == -1) continue;
                ret = min(ret,dp[len][i]);
            }
            printf("Case %d: %d
    ",kase++,ret == INT_MAX ? -1 : ret);
        }
        return 0;
    }
    View Code

    ZOJ 3228 Searching the String

    计算可重叠不可重叠字串出现在主串的次数

    可重叠就是裸地AC自动机。

    不可重叠,记录字典树上每个点的深度,没匹配到一个模式串,记录一下位置,

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXNNODE = 600010;
    const int SIGMA_SIZE = 26;
    const int INF = 0x3f3f3f3f;
    int pos[MAXNNODE / 6],N;
    char str[MAXNNODE / 6];
    
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int fail[MAXNNODE],last[MAXNNODE];
        int depth[MAXNNODE],pre[MAXNNODE];
        int cnt[MAXNNODE][2];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));}
        int idx(char c) {return c - 'a';}
    
        int insert(char * s,int v)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    depth[sz] = i + 1;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            val[u] += v;//最后的叶子节点给与信息v
            return u;
        }
    
        //建立字典树
    
        void get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int i,int j)
        {
            if (j)
            {
               // printf("%d
    ",val[j]);
                cnt[j][0]++;
                if (i - pre[j] >= depth[j])
                {
                    cnt[j][1]++;
                    pre[j] = i;
                }
                print(i,last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(i,j);
                else if (last[j]) print(i,last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
            memset(pre,-1,sizeof(pre));
            memset(cnt,0,sizeof(cnt));
            memset(val,0,sizeof(val));
        }
    }src;
    
    int flag[MAXNNODE / 6];
    int main()
    {
        int kase = 1;
        while (scanf("%s",str) != EOF)
        {
            scanf("%d",&N);
            src.init();
            for (int i = 0 ; i < N ; i++)
            {
                char tmp[10];
                scanf("%d%s",&flag[i],tmp);
                pos[i] = src.insert(tmp,1);
            }
            src.get_fail();
            src.Find(str);
            printf("Case %d
    ",kase++);
            for (int i = 0 ; i < N ; i++)
                printf("%d
    ",src.cnt[pos[i]][flag[i]]);
            puts("");
        }
        return 0;
    }
    View Code

    HDU 3247  Resource Archiver

    题目:给出n个资源,m个病毒,将资源串拼接成一个串,必须包含所有的资源串,可以重叠,但是不能包含病毒

    问最小的长度为多少

    所有的资源串和病毒串都放在Trie树里建立起来,当然作上相应的标记。然后建立fail指针之后

    从资源串的结尾出发,BFS,记录能到达其它资源串结尾的步数。得到所有资源串结尾状态的距离邻接阵。

    之后是状态压缩DP

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXNNODE = 60010;
    const int SIGMA_SIZE = 2;
    const int INF = 0x3f3f3f3f;
    int pos[12];
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int state[MAXNNODE];
        int fail[MAXNNODE],last[MAXNNODE];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));}
        int idx(char c) {if (c == '0') return 0 ; return 1;}
    
        void insert(char * s,bool v,int id = -1)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    state[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            if (!v)
            {
                pos[id] = u;
                state[u] |= (1 << id);
                //printf("%d %d
    ",u,state[u]);
            }
            val[u] = val[u] || v;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        void get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                val[r] |= val[fail[r]]; //use in dp problem
                state[r] |= state[fail[r]];
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
               // printf("%d
    ",val[j]);
                //cnt[val[j]]++;
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
            memset(val,0,sizeof(val));
            memset(state,0,sizeof(state));
        }
    }src;
    
    int dist[12][MAXNNODE];
    char str[1010];
    int length[20];
    int dp[12][2000];
    
    void bfs(int id,int st)
    {
        //printf("%d %d
    ",id,st);
        for (int i = 0 ; i < src.sz ; i++) dist[id][i] = INF;
        dist[id][st] = 0;
        queue<int>q;
        q.push(st);
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            int v = src.ch[u][0];
            if (!src.val[v] && dist[id][v] == INF)
            {
                dist[id][v] = dist[id][u] + 1;;
                q.push(v);
            }
            v = src.ch[u][1];
            if (!src.val[v] && dist[id][v] == INF)
            {
                dist[id][v] = dist[id][u] + 1;
                q.push(v);
            }
        }
    }
    
    void calcu(int n)
    {
        int limit = (1 << n);
        for (int i = 0 ; i <= n ; i++)
            for (int j = 0 ; j < limit ; j++) dp[i][j] = INF;
        for (int i = 0 ; i < n ; i++)
            dp[i][1 << i] = length[i];
        for (int i = 0 ; i < limit ; i++)
        {
            for (int j = 0 ; j < n ; j++)
            {
                if ((i & (1 << j)) && dp[j][i] != INF)
                {
                    for (int k = 0 ; k < n ; k++)
                    {
                        int nxt = i | src.state[pos[k]];
                        dp[k][nxt] = min(dp[k][nxt],dp[j][i] + dist[j][pos[k]]);
                    }
                }
            }
        }
        int ret = INF;
        for (int i = 0 ; i < n ; i++)
            ret = min(ret,dp[i][limit - 1]);
        printf("%d
    ",ret);
    }
    
    int main()
    {
        int N,M;
        while (scanf("%d%d",&N,&M) != EOF)
        {
            if (N == 0 && M == 0) break;
            src.init();
            memset(length,0,sizeof(length));
            for (int i = 0 ; i < N ; i++)
            {
                scanf("%s",str);
                length[i] = strlen(str);
                src.insert(str,false,i);
            }
            for (int i = 0 ; i < M ; i++)
            {
                scanf("%s",str);
                src.insert(str,true);
            }
            src.get_fail();
           // printf("%d
    ",src.sz);
           // for (int i = 0 ; i < 9 ; i++)printf("%d %d
    ",i,src.val[i]);
            for (int i = 0 ; i < N ; i++) bfs(i,pos[i]);
            calcu(N);
        }
        return 0;
    }
    View Code

    ZOJ 3494 BCD CODE

    题目:给出一些模式串,给出一个范围[A,B],求出区间内有多少个数,写成BCD之后,不包含模式串

    使用AC自动机,得到bcd[i][j]表示状态i,加了数字j以后到达的状态,为-1表示不能转移

    然后就是数位DP了

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXNNODE = 2010;
    const int SIGMA_SIZE = 2;
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int fail[MAXNNODE],last[MAXNNODE];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));}
        int idx(char c) {return c - '0';}
    
        void insert(char * s,int v)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            val[u] = v;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        void get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                if (val[fail[r]]) val[r] = 1;
                //val[r] += val[fail[r]]; use in dp problem
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
               // printf("%d
    ",val[j]);
               // cnt[val[j]]++;
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
            memset(val,0,sizeof(val));
        }
    }src;
    
    int bcd[MAXNNODE][20];
    int trans(int pre,int num)
    {
        if (src.val[pre]) return -1;
        int cur = pre;
        for (int i = 3 ; i >= 0 ; i--)
        {
            if (src.val[src.ch[cur][(num >> i) & 1]]) return -1;
            cur = src.ch[cur][(num >> i) & 1];
        }
        return cur;
    }
    
    void init()
    {
        for (int i = 0 ; i < src.sz ; i++)
            for (int j = 0 ; j < 10 ; j++)
                bcd[i][j] = trans(i,j);
    }
    
    const int MOD = 1000000009;
    LL dp[210][MAXNNODE];
    int digit[210];
    
    LL dfs(int length,int s,bool ismax,bool zero)
    {
        if (length == 0) return 1;
        if (!ismax && dp[length][s] >= 0) return dp[length][s];
        LL ans = 0;
        if (length > 1 && zero)
        {
            ans += dfs(length - 1,s,ismax && digit[length] == 0,true);
            ans %= MOD;
        }
        else
        {
            if (bcd[s][0] != -1)
            {
                ans += dfs(length - 1,bcd[s][0],ismax && digit[length] == 0,false);
                ans %= MOD;
            }
        }
        int limit = ismax ? digit[length] : 9;
        for (int i = 1 ; i <= limit ; i++)
        {
            if (bcd[s][i] != -1)
            {
                ans += dfs(length - 1,bcd[s][i],ismax && i == limit ,false);
                ans %= MOD;
            }
        }
        if (!ismax && !zero) dp[length][s] = ans;
        return ans;
    }
    
    LL calcu(char * s)
    {
        int len = strlen(s + 1);
        for (int i = 1,j = len ; i <= len ; i++,j--)
            digit[j] = s[i] - '0';
       // for (int j = 1 ; j <= len ; j++) printf("%d ",digit[j]); puts("");
        return dfs(len,0,true,true);
    }
    
    char str[210];
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            int n;
            src.init();
            scanf("%d",&n);
            for (int i = 0 ; i < n ; i++)
            {
                scanf("%s",str);
                src.insert(str,1);
            }
            src.get_fail();
            init();
            memset(dp,-1,sizeof(dp));
            LL ans = 0;
            scanf("%s",str + 1);
            int len = strlen(str + 1);
            for (int i = len ; i >= 1 ; i--)
            {
                if (str[i] > '0')
                {
                    str[i]--;
                    break;
                }
                else str[i] = '9';
            }
            ans -= calcu(str);
            ans %= MOD;
            //cout << calcu(str) << endl;
            scanf("%s",str + 1);
           // cout << calcu(str) << endl;
            ans += calcu(str);
            ans %= MOD;
            if (ans < 0) ans += MOD;
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code

    HDU 4758 Walk Through Squares

    题意:给n*m的地图,在地图的点上走,(n+1)*(m+1)个点,两种操作:往下走D和往右走R。现在要从左上角走到右下角,给定两个操作串,问包含这两个串的走法总共有多少种。

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MOD = 1e9 + 7;
    const int MAXNNODE = 420;
    const int SIGMA_SIZE = 2;
    int dp[110][110][220][4];
    int M,N;
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int fail[MAXNNODE],last[MAXNNODE];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));}
        int idx(char c)
        {
            if (c == 'R') return 0;
            else return 1;
        }
    
        void insert(char * s,int v)
        {
            int u = 0,n = strlen(s);
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (ch[u][c] == 0)
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            val[u] = v;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        void get_fail()
        {
            queue<int>q;
           // fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u != 0)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
                //else ch[0][c] = 0;
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                if(val[fail[r]]) val[r] |= val[fail[r]];
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                    val[u] |= val[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
               // printf("%d
    ",val[j]);
                //cnt[val[j]]++;
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
            memset(val,0,sizeof(0));
            val[0] = 0;
        }
    
        void slove()
        {
            memset(dp,0,sizeof(dp));
            dp[0][0][0][0] = 1;
            for (int i = 0 ; i <= M ; i++)
                for (int j = 0 ; j <= N; j++)
                    for (int s = 0 ; s < sz ; s++)
                        for (int k = 0 ; k < 4 ; k++)
            {
                if (dp[i][j][s][k] == 0) continue;
                int nxt = ch[s][0];
                if (i < M)
                    dp[i + 1][j][nxt][k | val[nxt]] = (dp[i + 1][j][nxt][k | val[nxt]]
                            + dp[i][j][s][k]) % MOD;
                nxt = ch[s][1];
                if (j < N)
                dp[i][j + 1][nxt][k | val[nxt]] = (dp[i][j + 1][nxt][k | val[nxt]]
                            + dp[i][j][s][k]) % MOD;
            }
            int ret = 0;
            for (int i = 0 ; i < sz ; i++)
                ret = (ret + dp[M][N][i][3]) % MOD;
            printf("%d
    ",ret);
        }
    }src;
    
    int main()
    {
        //freopen("sample.txt","r",stdin);
        int T;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d%d",&M,&N);
            src.init();
            for (int i = 0 ; i < 2; i++)
            {
                char str[210];
                scanf("%s",str);
                src.insert(str,1 << i);
            }
            src.get_fail();
            src.slove();
           // for (int i = 0 ; i < src.sz ; i++)
              //  printf("%d %d
    ",src.ch[i][0],src.ch[i][1]);
        }
        return 0;
    }
    View Code

    HDU 4511 小明系列故事――女友的考验

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const double INF = 1e20;
    const int MAXNNODE = 1010;
    const int SIGMA_SIZE = 51;
    double dp[60][MAXNNODE];
    int N,M;
    struct node
    {
        double x,y;
    }input[60];
    double dist(int i ,int j)
    {
        return sqrt((input[i].x - input[j].x) * (input[i].x - input[j].x) +
                (input[i].y - input[j].y) * (input[i].y - input[j].y));
    }
    struct Ac_Automation
    {
        int ch[MAXNNODE][SIGMA_SIZE];
        int val[MAXNNODE];
        int fail[MAXNNODE],last[MAXNNODE];
        int sz;
        Ac_Automation() {sz = 1;memset(ch[0],0,sizeof(ch[0]));}
        int idx(int c) {return c;}
    
        void insert(int * s,int v,int n)
        {
            int u = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(s[i]);
                if (!ch[u][c])
                {
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            val[u] = v;//最后的叶子节点给与信息v
        }
    
        //建立字典树
    
        void get_fail()
        {
            queue<int>q;
            fail[0] = 0;
            for (int c = 0 ; c < SIGMA_SIZE ; c++)
            {
                int u = ch[0][c];
                if (u)
                {
                    fail[u] = 0;
                    q.push(u);
                    last[u] = 0;
                }
            }
            while (!q.empty())
            {
                int r = q.front();q.pop();
                val[r] |= val[fail[r]];
                for (int c = 0 ; c < SIGMA_SIZE ; c++)
                {
                    int u = ch[r][c];
                    if (u == 0)
                    {
                        ch[r][c] = ch[fail[r]][c];
                        continue;
                    }
                    q.push(u);
                    int v = fail[r];
                    while (v && !ch[v][c]) v = fail[v];
                    fail[u] = ch[v][c];
                    last[u] = val[fail[u]] ? fail[u] : last[fail[u]];
                }
            }
        }
    
        void print(int j)
        {
            if (j)
            {
               // printf("%d
    ",val[j]);
                //cnt[val[j]]++;
                print(last[j]);
            }
        }
    
        void Find(char * T)
        {
            int n = strlen(T);
            int j = 0;
            for (int i = 0 ; i < n ; i++)
            {
                int c = idx(T[i]);
               // while(j && !ch[j][c]) j = f[j];
                j = ch[j][c];
                if (val[j]) print(j);
                else if (last[j]) print(last[j]);//print是功能函数
            }
        }
    
        void init()
        {
            sz = 1;
            memset(ch[0],0,sizeof(ch[0]));
        }
    
        double slove()
        {
            for (int i = 0 ; i < MAXNNODE ; i++)
                for (int j = 0 ; j < 60 ; j++) dp[j][i] = INF;
            dp[1][ch[0][1]] = 0.0;
            for (int i = 1 ; i <= N; i++)
                for (int j = 0 ; j < sz ; j++)
            {
                if (dp[i][j] == INF) continue;
                for (int k = i + 1; k <= N; k++)
                {
                    int nxt = ch[j][k];
                    if (val[nxt]) continue;
                    dp[k][nxt] = min(dp[k][nxt],dp[i][j] + dist(i,k));
                }
            }
            double ret = INF;
            for (int i = 0 ; i < sz ; i++)
                ret = min(ret,dp[N][i]);
            return ret;
        }
    }src;
    int main()
    {
       // freopen("sample.txt","r",stdin);
        while (scanf("%d%d",&N,&M) != EOF)
        {
            if (N == 0 && M == 0) break;
            src.init();
            for (int i = 1 ; i <= N; i++) scanf("%lf%lf",&input[i].x,&input[i].y);
            for (int i = 0 ; i < M; i++)
            {
                int k;
                scanf("%d",&k);
                int tmp[10];
                for (int i = 0 ; i < k ; i++) scanf("%d",&tmp[i]);
                src.insert(tmp,1,k);
            }
            src.get_fail();
            double ret = src.slove();
            if (ret == INF) puts("Can not be reached!");
            else printf("%.2lf
    ",ret);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    JSON使用——获取网页返回结果是Json的代码
    关于android:inputType属性的说明
    MySQL无视密码进入Server
    Linux下MySQL使用
    Linux下mv命令详解
    软件测试:测试用例
    软件测试:概述
    《零售业务中台架构设计探讨及实践》阅读笔记
    Python开发:OpenCV版本差异所引发的cv2.findContours()函数传参问题
    《小米网抢购系统开发实践》阅读笔记
  • 原文地址:https://www.cnblogs.com/Commence/p/5169002.html
Copyright © 2011-2022 走看看