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;
    }
    
  • 相关阅读:
    android讲义2之自定义view
    android讲义2之单项选择
    android讲义2之计时器组件Chronometer
    android讲义2之代码布局
    android讲义2之图片变换
    android讲义2之简单图片浏览器且有截图效果(对ImageView使用)
    android讲义2的相对布局(持续更新)
    android讲义2之在xml中设定imageButtion
    MoSH——移动设备上的Shell
    ArithmeticOperators.cs
  • 原文地址:https://www.cnblogs.com/Aya-Uchida/p/12325662.html
Copyright © 2011-2022 走看看