zoukankan      html  css  js  c++  java
  • bzoj1030 文本生成器

    题目链接

    题意

    给出(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;
    }
    
  • 相关阅读:
    LeetCode 295. Find Median from Data Stream (堆)
    LeetCode 292. Nim Game(博弈论)
    《JavaScript 模式》读书笔记(4)— 函数2
    《JavaScript 模式》读书笔记(4)— 函数1
    《JavaScript 模式》读书笔记(3)— 字面量和构造函数3
    《JavaScript 模式》读书笔记(3)— 字面量和构造函数2
    《JavaScript 模式》读书笔记(3)— 字面量和构造函数1
    《JavaScript 模式》读书笔记(2)— 基本技巧3
    《JavaScript 模式》读书笔记(2)— 基本技巧2
    《JavaScript 模式》读书笔记(2)— 基本技巧1
  • 原文地址:https://www.cnblogs.com/wxyww/p/10346927.html
Copyright © 2011-2022 走看看