Sockpuppets
建出trie树,那么匹配的东西一定是祖先关系。
记 f ( x , a , b ) f(x,a,b) f(x,a,b) 表示考虑了 x x x 的子树,祖先有 a a a 个小号匹配子树,子树有 b b b 个小号匹配祖先的方案数,背包转移即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 23456;
const int ALPHA = 26;
const int md = 1e9 + 7;
int n, m, root, total, type[N], go[N][ALPHA], dp[N][11][21];
char str[N];
inline void add(int &x, int y) {
x += y;
if (x >= md) {
x -= md;
}
}
inline int mul(int x, int y) {
return (long long)x * y % md;
}
inline int new_node() {
++total;
for (int i = 0; i < ALPHA; ++i) {
go[total][i] = 0;
}
type[total] = 0;
return total;
}
void dfs(int x) {
static int temp[11][21];
memset(dp[x], 0, sizeof dp[x]);
dp[x][0][0] = 1;
for (int i = 0; i < ALPHA; ++i) {
int y = go[x][i];
if (y) {
dfs(y);
}
}
for (int i = 0; i < ALPHA; ++i) {
int y = go[x][i];
if (y) {
for (int a = 0; a <= 10; ++a) {
for (int b = 0; b <= 20; ++b) {
if (!dp[x][a][b]) {
continue;
}
for (int aa = 0; aa <= 10 - a; ++aa) {
for (int bb = 0; bb <= 20 - b; ++bb) {
if (dp[y][aa][bb]) {
add(temp[a + aa][b + bb], mul(dp[x][a][b], dp[y][aa][bb]));
}
}
}
}
}
for (int a = 0; a <= 10; ++a) {
for (int b = 0; b <= 20; ++b) {
dp[x][a][b] = temp[a][b];
temp[a][b] = 0;
}
}
}
}
if (type[x] == 1) {
for (int a = 0; a <= 10; ++a) {
for (int b = 0; b <= 20; ++b) {
if (!dp[x][a][b]) {
continue;
}
add(temp[a][b], dp[x][a][b]);
if (a + 1 <= 10) {
add(temp[a + 1][b], dp[x][a][b]);
}
if (b - 1 >= 0) {
add(temp[a][b - 1], mul(b, dp[x][a][b]));
}
if (a + 2 <= 10) {
add(temp[a + 2][b], mul(md + 1 >> 1, dp[x][a][b]));
}
if (a + 1 <= 10 && b - 1 >= 0) {
add(temp[a + 1][b - 1], mul(b, dp[x][a][b]));
}
if (b - 2 >= 0) {
add(temp[a][b - 2], mul(b * (b - 1) / 2, dp[x][a][b]));
}
}
}
for (int a = 0; a <= 10; ++a) {
for (int b = 0; b <= 20; ++b) {
dp[x][a][b] = temp[a][b];
temp[a][b] = 0;
}
}
} else if (type[x] == 2) {
for (int a = 0; a <= 10; ++a) {
for (int b = 0; b <= 20; ++b) {
if (!dp[x][a][b]) {
continue;
}
add(temp[a][b], dp[x][a][b]);
if (a - 1 >= 0) {
add(temp[a - 1][b], mul(a, dp[x][a][b]));
}
if (b + 1 <= 20) {
add(temp[a][b + 1], dp[x][a][b]);
}
}
}
for (int a = 0; a <= 10; ++a) {
for (int b = 0; b <= 20; ++b) {
dp[x][a][b] = temp[a][b];
temp[a][b] = 0;
}
}
}
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
int tt;
scanf("%d", &tt);
for (int ttt = 1; ttt <= tt; ++ttt) {
scanf("%d %d", &n, &m);
total = 0;
root = new_node();
for (int i = 1; i <= n; ++i) {
scanf("%s", str);
int x = root;
for (int j = 0; str[j]; ++j) {
if (!go[x][str[j] - 'a']) {
go[x][str[j] - 'a'] = new_node();
}
x = go[x][str[j] - 'a'];
}
type[x] = 1;
}
for (int i = 1; i <= m; ++i) {
scanf("%s", str);
int x = root;
for (int j = 0; str[j]; ++j) {
if (!go[x][str[j] - 'a']) {
go[x][str[j] - 'a'] = new_node();
}
x = go[x][str[j] - 'a'];
}
type[x] = 2;
}
dfs(root);
printf("Case #%d: %d\n", ttt, dp[root][0][0]);
}
return 0;
}
Sequences Generator
先默认每个位置是最大概率的数,每次失配会让概率乘最多 1 2 \frac{1}{2} 21 ,用后缀数组暴力匹配,当概率小于 e p s eps eps 时直接返回 0 0 0 即可。
#include <bits/stdc++.h>
using namespace std;
typedef double ld;
const int N = 623456;
const int LOG = 20;
const ld eps = 1e-12;
int n, m, low[N], high[N], prob[N][10];
ld sum[N];
struct suffix_array_t {
int n, s[N], rank[N], array[N], height[N], length[N], rmq[LOG][N];
void init() {
static int temp[N], first[N], second[N], number[N];
for (int i = 1; i <= n; ++i) {
++number[s[i]];
}
for (int i = 1; i <= n; ++i) {
number[i] += number[i - 1];
}
for (int i = 1; i <= n; ++i) {
array[number[s[i]]--] = i;
}
for (int i = 1; i <= n; ++i) {
number[i] = 0;
}
rank[array[1]] = 1;
for (int i = 2; i <= n; ++i) {
rank[array[i]] = rank[array[i - 1]] + (s[array[i]] != s[array[i - 1]]);
}
for (int length = 1; rank[array[n]] != n; length <<= 1) {
for (int i = 1; i <= n; ++i) {
++number[second[i] = i + length > n ? 0 : rank[i + length]];
}
for (int i = 1; i <= n; ++i) {
number[i] += number[i - 1];
}
for (int i = 1; i <= n; ++i) {
temp[number[second[i]]--] = i;
}
for (int i = 0; i <= n; ++i) {
number[i] = 0;
}
for (int i = 1; i <= n; ++i) {
++number[first[i] = rank[i]];
}
for (int i = 1; i <= n; ++i) {
number[i] += number[i - 1];
}
for (int i = n; i; --i) {
array[number[first[temp[i]]]--] = temp[i];
}
for (int i = 1; i <= n; ++i) {
number[i] = 0;
}
rank[array[1]] = 1;
for (int i = 2; i <= n; ++i) {
rank[array[i]] = rank[array[i - 1]] + (first[array[i]] != first[array[i - 1]] || second[array[i]] != second[array[i - 1]]);
}
}
for (int i = 1, j = 0; i <= n; ++i) {
for (j -= j > 0; rank[i] != 1 && i + j <= n && array[rank[i] - 1] + j <= n && s[i + j] == s[array[rank[i] - 1] + j]; ++j);
height[rank[i]] = j;
}
for (int i = 2; i <= n; ++i) {
length[i] = length[i >> 1] + 1;
}
for (int i = 1; i <= n; ++i) {
rmq[0][i] = height[i];
}
for (int i = 1; i < LOG; ++i) {
for (int j = 1; j + (1 << i) - 1 <= n; ++j) {
rmq[i][j] = min(rmq[i - 1][j], rmq[i - 1][j + (1 << i - 1)]);
}
}
}
int lcp(int x, int y) {
if (x == y) {
return n - x + 1;
}
x = rank[x];
y = rank[y];
if (x > y) {
swap(x, y);
}
++x;
int k = length[y - x];
return min(rmq[k][x], rmq[k][y - (1 << k) + 1]);
}
} suffix_array;
ld solve(int l, int r, int ll, int rr, ld value) {
if (value < eps) {
return 0;
}
if (l > r) {
return value;
}
int lcp = suffix_array.lcp(l, ll);
if (lcp >= r - l + 1) {
return value * exp