DNA Sequence POJ - 2778
DNA Sequence POJ - 2778
又被poj教育了一晚上, ll 取膜会t就离谱, 淦
题面
题解
先看数据, m <= 10 且 |s| <= 10, n <= 2e9
明显n是不可能线性了, 考虑字符串吧
这么小的数据量, 要去想用 tire 存
然后不出现这些串, 就是所求串在trie上没匹配
既然要匹配每个串, 那直接trie变成Ac自动机吧
然后无非就是在自动机上 next 乱走只要不走到字符串的 尾节点(或者当前失配能走到其他串的尾节点)
就合法, 就变成了有多少长度为 n 的路径条数, 那就是矩阵快速幂了
~~t了一晚上, 吐了, ll取膜复杂度这么高的吗~
struct Martrix {
int n, m;
vector<VI> ma;
Martrix(int N = 0, int M = 0) : n(N), m(M) { ma.resize(N, VI(M)); }
Martrix operator*(const Martrix& a) {
Martrix ans(n, a.m);
rep(i, 0, n - 1) rep(j, 0, a.m - 1) {
rep(k, 0, m - 1) ans.ma[i][j] = (ans.ma[i][j] + (ll)ma[i][k] * a.ma[k][j]) % mod;
}
return ans;
}
};
struct AC {
static const int N = 2e2 + 5, M = 4; //字符串总长度, 字符范围
int trie[N][M], fail[N], q[N], tot;
bool tag[N];
void init() {
rep(i, 0, M - 1) trie[0][i] = 0;
tot = tag[0] = 0;
}
int newnode() {
fail[++tot] = 0; memset(trie[tot], 0, sizeof trie[tot]);
tag[tot] = 0; return tot;
}
int getCH(char c) { return c == 'A' ? 0 : c == 'C' ? 1 : c == 'G' ? 2 : 3; }
void insert(char* s) {
int p = 0;
for (int i = 0, ch = getCH(s[i]); s[i]; p = trie[p][ch], ch = getCH(s[++i]))
if (!trie[p][ch]) trie[p][ch] = newnode();
tag[p] = 1;
}
void build() {
int head = 0, tail = -1;
rep (i, 0, M - 1) if (trie[0][i]) q[++tail] = trie[0][i];
for (int p = q[head]; head <= tail; p = q[++head])
rep (i, 0, M - 1)
if (trie[p][i])
fail[trie[p][i]] = trie[fail[p]][i], q[++tail] = trie[p][i], tag[trie[p][i]] |= tag[fail[trie[p][i]]];
else trie[p][i] = trie[fail[p]][i];
}
} ac;
const int N = 4e1 + 5, M = 123 + 5;
int n, m, _, k;
char s[15];
Martrix a, b;
void getMartrix() {
a = Martrix(ac.tot + 1, ac.tot + 1); b = Martrix(ac.tot + 1, 1);
rep(i, 0, ac.tot) {
if (!ac.tag[i])
rep(j, 0, 3)
if (!ac.tag[ac.trie[i][j]]) ++a.ma[i][ac.trie[i][j]];
b.ma[i][0] = 1;
}
}
Martrix qpow(Martrix a, ll b) {
Martrix ans(a.n, a.m);
rep(i, 0, a.n - 1) ans.ma[i][i] = 1;
for (; b; b >>= 1, a = a * a)
if (b & 1) ans = ans * a;
return ans;
}
int main() {
IOS; cin >> m >> n; ac.init();
rep(i, 1, m) cin >> s, ac.insert(s);
ac.build(); getMartrix();
a = qpow(a, n) * b;
cout << a.ma[0][0];
return 0;
}