[JSOI2009]密码 AC自动机+状压DP+暴力搜索

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;
}

猜你喜欢

转载自blog.csdn.net/xgc_woker/article/details/80079884