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\n",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\n",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('\n');
        }
        printf("total: %d\n",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\n",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\n",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\n",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\n",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\n",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\n",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\n",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\n",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\n", 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\n",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\n",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\n",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\n",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] = '\0';
                    //len++;
                    int value = dp[i][j];
                    if (val[nxt]) value += h[val[nxt]];
                //    if (value != 0) printf("%s %d\n",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\n",MAX);
        printf("%s\n",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\n",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\n",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\n",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\n",kase++);
        for (int i = 0 ; i < N ; i++)
            printf("%d\n",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\n",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\n",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\n",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\n",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\n",src.sz);
       // for (int i = 0 ; i < 9 ; i++)printf("%d %d\n",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\n",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\n",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\n",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\n",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\n",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\n",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\n",ret);
    }
    return 0;
}
View Code

 

posted @ 2016-01-29 14:53  Commence  阅读(453)  评论(0编辑  收藏  举报