洛谷 4052 loj 10063 bzoj 1030 [JSOI2007]文本生成器 题解

博客观赏效果更佳

题意简述

你要求有多少个字符串,使得:

  1. 长度为m
  2. 包含至少一个给定的单词。会给定 n n 个单词。

1 e 4 + 7 1e4+7

思路框架

用总共的方案数减去一个单词都不包含的方案数。前面那个是 2 6 n 26^n ,后面那个在 A C AC 自动机上跑 D P DP 求解。

具体思路

首先,“至少一个”->“总共减去一个都没有”,是一个经典套路。这个不多说。

然后讲讲如何 d p dp 。设 d p [ i ] [ j ] dp[i][j] 表示,长度为 i i ,匹配到 A C AC 自动机的第 j j 个位置。在建立 f a i l fail 然后若合法,那么就从 d p [ i ] [ j ] dp[i][j] 转移到 d p [ i + 1 ] [ s o n ] dp[i+1][son] 。最后的答案是所有 d p [ m ] [ i ] dp[m][i] 的和。

实现注意

  1. AC自动机别写挂了
  2. 多开点空间,别怂

代码

#include<bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
	#define N 14444
	#define mod 10007
	#define F(i,l,r) for(int i=l;i<=r;++i)
	#define D(i,r,l) for(int i=r;i>=l;--i)
	#define Fs(i,l,r,c) for(int i=l;i<=r;c)
	#define Ds(i,r,l,c) for(int i=r;i>=l;c)
	#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
	#define MEM(x,a) memset(x,a,sizeof(x))
	#define FK(x) MEM(x,0)

	bool cxk[N];
	class Ah_Chtholly_Automaton
	{
	public:
		int tr[N][26];
		int tot;
		void Init()
		{
			FK(tr);
			tot=0;
		}
		int Insert(char s[])
		{
			int pos=0;
			for(int i=0;s[i];++i)
			{
				int c=s[i]-'A';
				if (!tr[pos][c])
				{
					tr[pos][c]=++tot;
				}
				pos=tr[pos][c];
			}
			cxk[pos]=1;
			return pos;
		}

		int fail[N];
		queue<int> Q;
		void BuildFail()
		{
			FK(fail);
			while(!Q.empty()) Q.pop();

			F(i,0,25) 
			{
				if (tr[0][i]) Q.push(tr[0][i]);
			}
			while(!Q.empty())
			{
				int u=Q.front();Q.pop();

				F(i,0,25)
				{
					if (tr[u][i])
					{
						fail[tr[u][i]]=tr[fail[u]][i];
						cxk[tr[u][i]]|=cxk[fail[tr[u][i]]];
                                                //是否合法的判断:如果fail不合法,那我也不合法
						Q.push(tr[u][i]);
					}
					else tr[u][i]=tr[fail[u]][i];
				}
			}
		}
	}AC;

	int n,m;
	int id[N];
	char tmp[N];
	void Input()
	{
		scanf("%d%d",&n,&m);
		AC.Init();
		F(i,1,n)
		{
			scanf("%s",tmp);
			id[i]=AC.Insert(tmp);
		}
	}

	int dp[110][N];
	int qpow(int a,int b,int m)
	{
		int r=1;
		while(b)
		{
			if (b&1) r=r*a%m;
			a=a*a%m,b>>=1;
		}
		return r;
	}
	void Soviet()
	{
		AC.BuildFail();
		dp[0][0]=1;
		F(i,0,m-1) F(j,0,AC.tot) F(k,0,25)
		{
			int ch=AC.tr[j][k];
			if (!cxk[ch])
			{
				dp[i+1][ch]+=dp[i][j];
				dp[i+1][ch]%=mod;
			}
		}

		int ans=qpow(26,m,mod);
		F(i,0,AC.tot) 
		{
			ans=(ans-dp[m][i]+mod)%mod;
		}
		printf("%d\n",ans);	
	}
	void IsMyWife()
	{
		Input();
		Soviet();
	}
}
int main()
{
	Flandre_Scarlet::IsMyWife();
	getchar();getchar();
	return 0;
}
发布了210 篇原创文章 · 获赞 8 · 访问量 9001

猜你喜欢

转载自blog.csdn.net/LightningUZ/article/details/103327226