题解 CF222E 【Decoding Genome】
看到题,感觉预处理下 \(O(nm)\) 可以很容易的做到。
大概处理下每一个串作为前缀,后缀所可以选择的数的数量。
然后直接枚举,然后转移就行了。
再看一眼数据范围, \(n \le 10 ^ 15\)。
那没事了,很显然的矩乘的数据范围。
但是矩乘就不可以这么做了,要换一种转移方法。
你考虑把矩阵建成一个 \(50 \times 50\) 的矩阵,每一位 \((a,b)\) 的意义是 \(a\) 后面能否有 \(b\)
然后直接转移就行了。
感觉挺裸的,所以没太详细讲,不会矩乘的可以看下我的 博客
也可以私信。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define Rep(x, a, b) for(int x = a; x <= b; ++ x)
#define Dep(x, a, b) for(int x = a; x >= b; -- x)
#define Next(i, x) for(int i = head[x]; i; i = e[i].nxt)
int read() {
char c = getchar(); int f = 1, x = 0;
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
const int XRZ = 1e9 + 7;
char s[3]; int n, ans, p = 1, x, y;
struct node { int a[53][53], n, m; node() {memset(a, 0, sizeof(a)); }} a, b, c;
node operator * ( node &a, const node &b) {
node c; c.n = a.n; c.m = b.m;
Rep(i, 0, a.n - 1) Rep(j, 0, a.m - 1) Rep(k, 0, b.m - 1) c.a[i][k] = (c.a[i][k] + a.a[i][j] * b.a[j][k]) % XRZ;
return c;
}
node qpow(int y) {
node ans = c, base = b;
while(y) {
ans = ans * ans;
if(y & n) ans = ans * base;
y >>= 1;
} return ans;
}
signed main() {
n = read() - 1; int m = read(), k = read();
a.n = 1, a.m = m, b.n = b.m = m, c.n = c.m = m;
Rep(i, 0, m - 1) {
a.a[0][i] = 1, c.a[i][i] = 1;
Rep(j, 0, m - 1) b.a[i][j] = 1;
}
Rep(i, 0, k - 1) { scanf("%s", s);
if(s[0] >= 'a' && s[0] <= 'z') x = s[0] - 'a';
else x = s[0] - 'A' + 26;
if(s[1] >= 'a' && s[1] <= 'z') y = s[ 1 ] - 'a';
else y = s[1] - 'A' + 26; b.a[y][x] = 0;
}
while(p <= n) p <<= 1; p >>= 1;
a = a * qpow(p);
Rep(i, 0, m - 1) ans = (ans + a.a[0][i]) % XRZ;
printf("%lld\n", ans);
return 0;
}