[TJOI2018] 碱基序列

[题目链接]

         https://www.lydsy.com/JudgeOnline/problem.php?id=5337

[算法]

         考虑构建后缀自动机

         用fi , j表示前i个串 , 匹配到自动机上的j号节点方案数

         在自动机上dp即可 ,  详见代码 

         时间复杂度 : O(NK)

[代码]

       

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N = 20010;
const int ALPHA = 26;
const int P = 1e9 + 7;

#define rint register int

int k;
char s[N];

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
    x *= f;
}

struct Suffix_Automaton
{
        int sz , last;
        int father[N] , child[N][ALPHA] , depth[N] , dp[2][N] , size[N];
        vector< int > a[N];
        Suffix_Automaton()
        {
                sz = 1;
                last = 1;
        }
        inline int new_node(int dep)
        {
                depth[++sz] = dep;
                father[sz] = 0;
                memset(child[sz] , 0 , sizeof(child[sz]));
                return sz;
        }
        inline void extend(int ch)
        {
                int np = new_node(depth[last] + 1);
                int p = last;
                for (; child[p][ch] == 0; p = father[p]) 
                        child[p][ch] = np;
                if (child[p][ch] == np)
                        father[np] = 1;
                else
                {
                        int q = child[p][ch];
                        if (depth[q] == depth[p] + 1)
                                father[np] = q;
                        else
                        {
                                int nq = new_node(depth[last] + 1);
                                father[nq] = father[q];
                                father[np] = father[q] = nq;
                                memcpy(child[nq] , child[q] , sizeof(child[nq]));
                                for (; child[p][ch] == q; p = father[p])
                                        child[p][ch] = nq;
                        }
                }
                last = np;
                size[np] = 1;
        }
        inline void insert(char *s)
        {
                last = 1;
                for (rint i = 1; i <= strlen(s + 1); ++i)
                        extend(s[i] - 'A');        
        }        
        inline void dfs(int u , int par)
        {
                for (unsigned i = 0; i < a[u].size(); ++i)
                {
                        if (a[u][i] != par)
                        {
                                dfs(a[u][i] , u);
                                size[u] += size[a[u][i]];
                        }
                }
        }
        inline void update(int &x , int y)
        {
                x += y;
                while (x >= P) x -= P; 
        } 
        inline int find(int now , char *s)
        {
                for (rint i = 1; i <= strlen(s + 1); ++i)
                        if (!child[now][s[i] - 'A']) return -1;
                        else now = child[now][s[i] - 'A'];
                return now;
        }
        inline void calc()
        {
                for (rint i = 2; i <= sz; ++i)
                        a[father[i]].push_back(i);
                dfs(1 , 0);
                dp[0][1] = 1;
                for (rint i = 1; i <= k; ++i)
                {
                        int cnt;
                        int now = i & 1 , pre = now ^ 1;
                        read(cnt);
                        for (rint j = 1; j <= sz; ++j) dp[now][j] = 0;
                        for (rint j = 1; j <= cnt; ++j)
                        {
                                scanf("%s" , s + 1);
                                for (rint frm = 1; frm <= sz; ++frm)
                                {
                                        int to = find(frm , s);
                                        if (to != -1) 
                                                update(dp[now][to] , dp[pre][frm]);
                                }
                        }
                }
                int ans = 0;
                for (rint i = 1; i <= sz; ++i) 
                        update(ans , 1LL * size[i] * dp[k & 1][i] % P);
                printf("%d\n" , ans);
        }
} SAM;

int main()
{
        
        read(k); 
        scanf("%s" , s + 1);
        SAM.insert(s);
        SAM.calc();
        
        return 0;
    
}

 

posted @ 2019-04-05 21:25  evenbao  阅读(540)  评论(0编辑  收藏  举报