bzoj1030 文字生成器

wxyww發表於2019-02-01

題目連結

題意

給出(n)個字串,要構造一個長度為(m)的字串(S),使得給出的(n)個字串中至少有一個是(S)的子串。問方案數。

思路

(AC)自動機+(DP)
考慮至少有一個是S的子串不好考慮。考慮用全部情況減去其中不包含任何一個字串的情況。
全部情況就是(26^m),然後考慮怎麼求出不包含任何一個字串的情況。
(f[i][j])表示已經確定了(i)個字元,現在到了(AC)自動機的j位置的方案數。
顯然如果(j)位置是給出字串的結尾或者沿著(fail)指標可以跳到給出字串的結尾,那麼就不能轉移。其他的就可以轉移到(f[i + 1][k])(k)(j)(AC)自動機上的一個兒子。
最後答案就是(26^m-sumlimits_{i = 0}^{tot}f[m][i](i不是給出字串的結尾))

程式碼

/*
* @Author: wxyww
* @Date:   2019-02-01 19:33:15
* @Last Modified time: 2019-02-01 20:04:44
*/
#include<cstring>
#include<queue>
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<bitset>
using namespace std;
typedef long long ll;
const int N = 6000 + 10,mod = 10007;
ll read() {
    ll x=0,f=1;char c=getchar();
    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;
}
char s[110];
queue<int>q;
int trie[N][27],bz[N],fail[N],tot;
void ins() {
    int len = strlen(s + 1);
    int now = 0;
    for(int i = 1;i <= len;++i) {
        int x = s[i] - `A`;
        if(!trie[now][x]) trie[now][x] = ++tot;
        now = trie[now][x];
    }
    bz[now] = 1;
}
void get_fail() {
    for(int i = 0;i < 26;++i) if(trie[0][i]) q.push(trie[0][i]);
    while(!q.empty()) {
        int u = q.front();q.pop();
        bz[u] |= bz[fail[u]];
        for(int i = 0;i < 26;++i) {
            if(trie[u][i]) fail[trie[u][i]] = trie[fail[u]][i],q.push(trie[u][i]);
            else trie[u][i] = trie[fail[u]][i];
        }
    }
}
int qm(int x,int y) {
    int ans = 1;
    for(;y;y >>= 1,x = 1ll * x * x % mod) {
        if(y & 1) ans = 1ll * ans * x % mod;
    }
    return ans;
}
int f[N][N];
int main() {
    int n = read(),m = read();
    for(int i = 1;i <= n;++i) {
        scanf("%s",s + 1);
        ins();
    }
    get_fail();
    f[0][0] = 1;

    for(int i = 0;i < m;++i) {
        for(int j = 0;j <= tot;++j) {
            if(bz[j] || !f[i][j]) continue;
            for(int k = 0;k < 26;++k) {
                int z = trie[j][k];
                f[i + 1][z] += f[i][j];
                f[i + 1][z] >= mod ? f[i + 1][z] -= mod : 0;
            }
        }
    }
    int ans = qm(26,m);
    for(int i = 0;i <= tot;++i) {
        if(!bz[i]) ans = (ans - f[m][i] + mod) % mod;
    }
    cout<<ans;
    return 0;
}

相關文章