充斥着浓浓的乱搞气息.

Description

给一个母串, 和若干个子串. 问把每个子串放到可以匹配的某个位置上, 可以互相重叠, 最大和最小的覆盖长度是多少. 字串个数$\le 4$, 母串长$\le 10000$.

Solution

最大贪心, 最小DP:

解法稍后补.

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
#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e+4 + 5;

char line[maxn], mo[4][maxn];
int n, len, nxt[maxn], l[4], idx[4];
int MatchCount[4], pos[4][maxn], Matchable[4][maxn];
int ban[4];
int f[20][maxn], g[20][maxn], q[20][maxn];
int op[20], ed[20];

void KMP(int id, char *str, char *mod) {//str : origin, mod : small
int n = strlen(str + 1), m = strlen(mod + 1);
memset(nxt, 0, sizeof nxt);
memset(Matchable[id], 0, sizeof (int) * maxn);
int j = 0; nxt[1] = 0;
for (int i = 2; i <= m; ++i) {
while (j && mod[j + 1] != mod[i]) j = nxt[j];
if (mod[j + 1] == mod[i]) nxt[i] = ++j;
else nxt[i] = 0;
}
j = 0; MatchCount[id] = 0;
for (int i = 1; i <= n; ++i) {
while (j && mod[j + 1] != str[i]) j = nxt[j];
if (mod[j + 1] == str[i]) ++j;
if (j == m) {
pos[id][++MatchCount[id]] = i - m + 1;
Matchable[id][i] = 1;
j = nxt[j];
}
}
}
inline bool cmp(int a, int b) {
return l[a] > l[b];
}

namespace MaxValue {
void solve() {
int ans = 0;
int *Permutation = new int[n];
for (int i = 0; i < n; ++i) Permutation[i] = i;
memset(Matchable, 0, sizeof Matchable);
do {
int Limit = (1 << (n - 1)) - 1;
for (int S = 0; S <= Limit; ++S) {
int x = pos[idx[Permutation[0]]][1] + l[idx[Permutation[0]]] - 1;
int res = l[idx[Permutation[0]]];
ans = max(ans, res);
bool flg = false;
for (int i = 1; i < n; ++i) {
int index = upper_bound(pos[idx[Permutation[i]]] + 1,
pos[idx[Permutation[i]]] +
MatchCount[idx[Permutation[i]]] + 1,
x) - pos[idx[Permutation[i]]];
if (S & (1 << (i - 1))) {
if (index <= MatchCount[idx[Permutation[i]]] &&
pos[idx[Permutation[i]]][index] > x) {
res += l[idx[Permutation[i]]];
x = pos[idx[Permutation[i]]][index] + l[idx[Permutation[i]]] - 1;
} else {
flg = true;
break;
}
} else {
index--;
if (index && pos[idx[Permutation[i]]][index] <= x) {
res += l[idx[Permutation[i]]] -
(x - pos[idx[Permutation[i]]][index] + 1);
x = pos[idx[Permutation[i]]][index] + l[idx[Permutation[i]]] - 1;
} else {
flg = true;
break;
}
}
if (!flg) ans = max(ans, res);
}
}
} while(next_permutation(Permutation, Permutation + n));
printf("%d\n", ans);
delete[] Permutation;
}
}
namespace MinValue {
inline bool check(char *moA, char *moB) {
int n = strlen(moA + 1), m = strlen(moB + 1);
for (int i = 1; i <= n - m + 1; ++i) {
bool flg = false;
for (int j = 1; j <= m; ++j)
if (moB[j] != moA[i + j - 1]) {
flg = true;
break;
}
if (!flg) return true;
}
return false;
}
void solve() {
int Origin = (1 << n) - 1, Limit(Origin);
memset(ban, 0, sizeof ban);
for (int i = 0; i < n - 1; ++i)
for (int j = i + 1; j < n; ++j)
if (!ban[idx[j]] && check(mo[idx[i]], mo[idx[j]]))
ban[idx[j]] = 1, Origin ^= (1 << j);
memset(f, 0x3f, sizeof f);
memset(g, 0x3f, sizeof g);
memset(f[0], 0, sizeof f[0]);
memset(g[0], 0, sizeof g[0]);
for (int i = 0; i <= Limit; ++i) op[i] = 1, ed[i] = 0;
for (int i = 1; i <= len; ++i) {
for (int S = 1; S <= Limit; ++S) {
if (S & (S ^ Origin)) continue;
g[S][i] = g[S][i - 1];
for (int j = 0; j < n; ++j) {
if ((S & (1 << j)) && Matchable[idx[j]][i]) {
int preS = (S ^ (1 << j));
if (i - l[idx[j]] >= 0)
f[S][i] = min(f[S][i], g[preS][i - l[idx[j]]] + l[idx[j]]);
while (op[preS] <= ed[preS] && q[preS][op[preS]] + l[idx[j]] <= i)
++op[preS];
if (op[preS] <= ed[preS])
f[S][i] = min(f[S][i],
f[preS][q[preS][op[preS]]] -
q[preS][op[preS]] + i);
while (op[S] <= ed[S] && f[S][q[S][ed[S]]] - q[S][ed[S]] >= f[S][i] - i)
--ed[S];
q[S][++ed[S]] = i;
g[S][i] = min(g[S][i], f[S][i]);
}
}
}
}
printf("%d ", g[Origin][len]);
}
}ty

int main() {
int T; scanf("%d", &T);
while (T--) {
scanf("%s", line + 1); len = strlen(line + 1);
scanf("%d", &n);
for (int i = 0; i < n; ++i)
scanf("%s", mo[i] + 1), l[i] = strlen(mo[i] + 1);
for (int i = 0; i < n; ++i)
idx[i] = i;
sort(idx, idx + n, [](int a, int b) -> bool {return l[a] > l[b];});
for (int i = 0; i < n; ++i)
KMP(idx[i], line, mo[idx[i]]);
MinValue::solve();
MaxValue::solve();
}
return 0;
}