[poj2778 DNA Sequence]AC自动机,矩阵快速幂

题意:给一些字符串的集合S和整数n,求满足

  • 长度为n
  • 只含charset = {'A'、'T‘、'G'、'C'}包含的字符
  • 不包含S中任一字符串 

的字符串的种类数。

思路:首先对S建立ac自动机,考虑向ac自动机中的每种状态后加charset中的字符,如果终态不为“接受状态”,也就是不与S中的任一字符串匹配,则将这次转移记为有效,方法数加1。这样可以建立状态之间的转移矩阵D,表示由一个状态接受1个字符后的方案数,D自乘n次,就得到了任一状态接受n个字符形成的不同字符串种类数,其中从“0”到“i”的方案都要加到答案里面。

另外,这题的模比较有意思,为100000,既不大也不小,或者说是个比较猥琐的数。对于100*100的矩阵,这样取模当然是吃不消的,方法是对每个点算完后一次性取模。时间由800ms→125ms。

 

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#pragma comment(linker, "/STACK:10240000")
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <deque>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define X                   first
#define Y                   second
#define pb                  push_back
#define mp                  make_pair
#define all(a)              (a).begin(), (a).end()
#define fillchar(a, x)      memset(a, x, sizeof(a))
#define fillarray(a, b)     memcpy(a, b, sizeof(a))

typedef long long ll;
typedef pair<int, int> pii;
typedef unsigned long long ull;

#ifndef ONLINE_JUDGE
namespace Debug {
void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);}
void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R>
void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1;
while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T>
void print(const T t){cout<<t<<endl;}template<typename F,typename...R>
void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T>
void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;}
}
#endif // ONLINE_JUDGE

template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);}
template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);}

const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const double EPS = 1e-14;

/* -------------------------------------------------------------------------------- */

const int maxn = 107;
const int mod = 100000;

int N;

struct Matrix {
    ll a[maxn][maxn];

    Matrix() {
        for (int i = 0; i < N; i ++) {
            for (int j = 0; j < N; j ++) {
                a[i][j] = 0;
            }
        }
    }

    static Matrix unit() {
        Matrix ans;
        for (int i = 0; i < N; i ++) ans.a[i][i] = 1;
        return ans;
    }

    Matrix &operator * (const Matrix &that) const {
        static Matrix ans;
        for (int i = 0; i < N; i ++) {
            for (int j = 0; j < N; j ++) {
                ans.a[i][j] = 0;
                for (int k = 0; k < N; k ++) {
                    ans.a[i][j] += a[i][k] * that.a[k][j];
                }
                ans.a[i][j] %= mod;
            }
        }
        return ans;
    }

    static Matrix power(Matrix a, int n) {
        Matrix ans = unit(), buf = a;
        while (n) {
            if (n & 1) ans = ans * buf;
            buf = buf * buf;
            n >>= 1;
        }
        return ans;
    }
};

struct AC_automaton {
    const static int SZ = 4;
    int f[maxn], last[maxn];
    bool val[maxn];
    int ch[maxn][SZ];
    int sz;

    int idx(char ch) {
        if (ch == 'A') return 0;
        if (ch == 'T') return 1;
        if (ch == 'G') return 2;
        if (ch == 'C') return 3;

    }

    void init() {
        sz = 1;
        memset(ch[0], 0, sizeof(ch[0]));
    }

    void insert(char s[]) {
        int u = 0;
        for (int i = 0; s[i]; 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] = true;
    }

    void build() {
        queue<int> Q;
        f[0] = 0;
        for (int c = 0; c < SZ; c ++) {
            int u = ch[0][c];
            if (u) {
                f[u] = 0;
                Q.push(u);
                last[u] = 0;
            }
        }
        while (!Q.empty()) {
            int r = Q.front(); Q.pop();
            for (int c = 0; c < SZ; c ++) {
                int u = ch[r][c];
                if (!u) {
                    ch[r][c] = ch[f[r]][c];
                    continue;
                }
                Q.push(u);
                int v = f[r];
                while (v && !ch[v][c]) v = f[v];
                f[u] = ch[v][c];
                last[u] = val[f[u]]? f[u] : last[f[u]];
            }
        }
    }

    void solve(int m) {
        N = sz;
        Matrix ans;
        //Debug::print(sz);
        for (int i = 0; i < sz; i ++) {
            for (int j = 0; j < 4; j ++) {
                if (!val[ch[i][j]] && !last[ch[i][j]]) {
                    ans.a[i][ch[i][j]] ++;
                }
            }
        }
        ans = Matrix::power(ans, m);
        int rst = 0;
        for (int i = 0; i < sz; i ++) {
            rst = (rst + ans.a[0][i]) % mod;
        }
        printf("%d\n", rst);
    }

};

AC_automaton ac;


int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
    int n, m;
    char s[20];
    while (cin >> n >> m) {
        ac.init();
        for (int i = 0; i < n; i ++) {
            scanf("%s", s);
            ac.insert(s);
        }
        ac.build();
        ac.solve(m);
    }
    return 0;
}
posted @ 2015-08-25 03:22  jklongint  阅读(282)  评论(0)    收藏  举报