zoukankan      html  css  js  c++  java
  • 洛谷P4052 [JSOI2007]文本生成器 AC自动机上dp

    网址:https://www.luogu.com.cn/problem/P4052

    题意:

    给出$n$个长度为$m$的字符串,求长度为$k$的仅包含大写字母的字符串中至少包含一个给定的字符串的字符串的数量,结果对$10007$取模$(n leq 60,m leq 100,k leq 1200)$。

    题解:

    正向考虑似乎比较困难,要找恰好有$1,2,......n$个模式串的字符串。所以我们反向考虑,求所有方案减去一个模式串都没有的方案。这里我们考虑$AC$自动机。

    我们在POJ2778讨论了常见的$AC$自动机上$dp$的两种方法。我们考虑第二种,其时间复杂度是$O(n^3m^3logk)$显然无法通过。现在考虑第一种,其时间复杂度是$O(nmk)$,可以通过,然后我们就按照$dp$方程求解即可,$ans=26^n- sum _{0<i leq n*m} dp(k,i)$。

    AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int mod = 10007;
    const int N = 6e3 + 5;
    const int M = 26;
    int trie[N][M], fail[N];
    int dp[N][N];
    bool f[N];
    int cnt;
    void insert(char* s, int len)
    {
    	int root = 0;
    	for (int i = 0; i < len; ++i)
    	{
    		int nxt = s[i] - 'A';
    		if (!trie[root][nxt])
    			trie[root][nxt] = ++cnt;
    		root = trie[root][nxt];
    	}
    	f[root] = 1;
    }
    void get_fail()
    {
    	queue<int>q;
    	for (int i = 0; i < M; ++i)
    		if (trie[0][i])
    			q.push(trie[0][i]);
    	while (!q.empty())
    	{
    		int now = q.front();
    		q.pop();
    		for (int i = 0; i < M; ++i)
    		{
    			if (trie[now][i])
    			{
    				fail[trie[now][i]] = trie[fail[now]][i];
    				f[trie[now][i]] |= f[fail[trie[now][i]]];
    				q.push(trie[now][i]);
    			}
    			else
    				trie[now][i] = trie[fail[now]][i];
    		}
    	}
    }
    int pow(int a, int b, int p)
    {
    	int res = 1;
    	while (b)
    	{
    		if (b & 1)
    			res = res * a % p;
    		a = a * a % p;
    		b >>= 1;
    	}
    	return res;
    }
    void solve(int n)
    {
    	dp[0][0] = 1;
    	for (int i = 1; i <= n; ++i)
    		for (int j = 0; j <= cnt; ++j)
    			if (!f[j])
    				for (int k = 0; k < M; ++k)
    				{
    					dp[i][trie[j][k]] += dp[i - 1][j];
    					dp[i][trie[j][k]] %= mod;
    				}
    	int ans = 0;
    	for (int i = 0; i <= cnt; ++i)
    		if (!f[i])
    			(ans += dp[n][i]) %= mod;
    	printf("%d", (pow(26, n, mod) - ans % mod + mod) % mod);
    }
    char s[105];
    int main()
    {
    	int n, m;
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= n; ++i)
    	{
    		scanf("%s", s);
    		insert(s, strlen(s));
    	}
    	get_fail();
    	solve(m);
    	return 0;
    }
    
  • 相关阅读:
    关于MFC库和CRT库冲突的分析
    C++ Traits技术
    C/C++的参数传递机制
    C++与正态分布
    前端JavaScript
    python 前端 css
    python 前端 html
    MySQL 数据库
    网络编程 生产者消费者模型 GiL

  • 原文地址:https://www.cnblogs.com/Aya-Uchida/p/12325662.html
Copyright © 2011-2022 走看看