Description
给出N个子串,要求这N个子串在长度为L的串中都出现过。
求所有L的可能的总数,如果ans<=42,则你需按字典序输出所有L的可能的串。
Sample Input
10 2
hello
world
Sample Output
2
helloworld
worldhello
可能是我刚做完文本生成,感觉这一题的第一问其实不是很难。。。
首先先去一个重,然后考虑N的范围这么小,你就状压一下,做一下DP。
然后是第二问,好恶心啊,我搞了好久。。。
因为你考虑ans<=42的话,则所有的子串必定是紧紧相连的,你考虑有一个空位,答案最起码都会上50.,于是就n^n爆搜,做一点小优化,就能过了。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
struct trnode {
int v[30], fail, s;
trnode() {memset(v, -1, sizeof(v));}
} t[260]; int cnt;
int len, L; LL f[2][260][1100];
int head, tail, plen, list[260], rank[50];
char ss[11][26], s1[11][26], pp[50][26], c[26], b[26];
bool v[11];
void bt(int now) {
int x = 0;
int len = strlen(ss[now] + 1);
for(int i = 1; i <= len; i++) {
int y = ss[now][i] - 'a' + 1;
if(t[x].v[y] == -1) t[x].v[y] = ++cnt;
x = t[x].v[y];
} t[x].s |= 1 << (now - 1);
}
void get_fail() {
head = 1, tail = 2; list[1] = 0;
while(head != tail) {
int x = list[head];
for(int i = 1; i <= 26; i++) {
int y = t[x].v[i];
if(y == -1) continue;
if(x == 0) t[y].fail = 0;
else {
int j = t[x].fail;
while(j && t[j].v[i] == -1) j = t[j].fail;
t[y].fail = _max(t[j].v[i], 0);
}
list[tail++] = y;
}
head++;
}
}
void dfs(int x, int p) {
if(x == len + 1) {
if(p != L) return ;
++plen;
for(int i = 1; i <= p; i++) pp[plen][i] = c[i];
return ;
}
for(int i = 1; i <= len; i++) if(!v[i]){
v[i] = 1; int u = strlen(ss[i] + 1);
bool hh = 0;
for(int j = 1; j <= L; j++) b[j] = c[j];
for(int j = _max(1, p - u); j <= p; j++) {
if(j + u - 1 > L) break;
bool bk = 1;
for(int k = j; k <= p; k++) {
if(c[k] != ss[i][k - j + 1]) {
bk = 0;
break;
}
}
if(bk == 0) continue;
for(int k = p + 1; k <= j + u - 1; k++) c[k] = ss[i][k - j + 1];
hh = 1;
dfs(x + 1, j + u - 1);
break;
}
if(hh == 0 && p + u <= L) {
for(int j = p + 1; j <= p + u; j++) c[j] = ss[i][j - p];
dfs(x + 1, p + u);
}
for(int j = 1; j <= L; j++) c[j] = b[j];
v[i] = 0;
}
}
bool cmp(int a, int b) {
for(int i = 1; i <= L; i++) {
if(pp[a][i] < pp[b][i]) return 1;
else if(pp[a][i] > pp[b][i]) return 0;
}
return 1;
}
bool cmp2(char *a, char *b) {
int len1 = strlen(a + 1), len2 = strlen(b + 1);
if(len1 > len2) return 0;
for(int i = 1; i <= len2 - len1 + 1; i++) {
bool bk = 0;
for(int j = i; j <= i + len1; j++) {
if(b[j] != a[j - i + 1]) {
bk = 1;
break;
}
}
if(bk == 0) return 1;
}
return 0;
}
int main() {
int n; scanf("%d%d", &L, &n);
for(int i = 1; i <= n; i++) scanf("%s", s1[i] + 1);
for(int i = 1; i <= n; i++) {
bool bk = 0;
for(int j = 1; j <= n; j++) if(i != j){
if(cmp2(s1[i], s1[j])) {
bk = 1;
break;
}
}
if(bk == 0) {
++len;
for(int j = 1; j <= strlen(s1[i] + 1); j++) ss[len][j] = s1[i][j];
}
}
for(int i = 1; i <= len; i++) bt(i);
get_fail();
f[0][0][0] = 1; int now = 0;
for(int i = 1; i <= L; i++) {
now ^= 1;
memset(f[now], 0, sizeof(f[now]));
for(int j = 0; j <= cnt; j++) {
for(int k = 0; k < (1 << len); k++) if(f[now ^ 1][j][k]){
for(int o = 1; o <= 26; o++) {
int u = j;
while(u && t[u].v[o] == -1) u = t[u].fail;
if(t[u].v[o] == -1) f[now][0][k] += f[now ^ 1][j][k];
else f[now][t[u].v[o]][k | t[t[u].v[o]].s] += f[now ^ 1][j][k];
}
}
}
}
LL ans = 0;
for(int i = 0; i <= cnt; i++) ans += f[now][i][(1 << len) - 1];
printf("%lld\n", ans);
if(ans <= 42 && ans != 0) {
dfs(1, 0);
for(int i = 1; i <= plen; i++) rank[i] = i;
sort(rank + 1, rank + plen + 1, cmp);
for(int i = 1; i <= plen; i++) {
for(int j = 1; j <= L; j++) printf("%c", pp[rank[i]][j]);
printf("\n");
}
}
return 0;
}