把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

P2292 [HNOI2004]L语言

题面传送门
数据这么大显然是要我们用线性算法。
考虑把这个东西放到AC自动机上,预处理出每个节点能从哪些位置转移,这样的复杂度是\(O(m|s||t|+n|s|)\)的,不是很优秀,可能会被卡满。
发现dp转移方程是一个或的形式,也就是只要有一个为\(1\)即可而并不要求是哪一个为\(1\),所以就可以考虑状压,在AC自动机上状压前\(10\)个哪些可以转移,转移时维护一个dp数组上的前\(10\)个转移状态,与一下即可。
时间复杂度\(O(m|t|+n|s|)\)就可以过了。
代码实现:

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int n,m,k,x,y,z,cnt,dp[2000039],ans[239],flag[239],pus,now,tot;
char s[139],t[2000039];
struct AC{int son[26],fail;}f[239];
inline void get(){
	register int i;now=0;
	for(i=1;i<=k;i++) now=f[now].son[s[i]-'a']?f[now].son[s[i]-'a']:(f[now].son[s[i]-'a']=++cnt);ans[now]|=1<<k-1;
}
queue<int> q;
inline void bfs(){
	register int i;
	for(i=0;i<=25;i++) if(f[0].son[i]) q.push(f[0].son[i]);
	while(!q.empty()){
		now=q.front();q.pop();
		for(i=0;i<=25;i++){
			if(f[now].son[i]) f[f[now].son[i]].fail=f[f[now].fail].son[i],q.push(f[now].son[i]);
			else f[now].son[i]=f[f[now].fail].son[i];
		}
	}
}
inline void dfs(int x){
	if(!x||flag[x]) return;flag[x]=1;
	dfs(f[x].fail);ans[x]|=ans[f[x].fail];
}
int main(){
//	freopen("1.in","r",stdin);
	register int i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)scanf("%s",s+1),k=strlen(s+1),get();bfs();
	for(i=1;i<=cnt;i++) dfs(i);
	for(i=1;i<=m;i++){
		for(j=1;j<=k;j++) dp[j]=0;dp[0]=1;now=0;pus=1;
		scanf("%s",t+1);k=strlen(t+1);tot=0;
		for(j=1;j<=k;j++){
			now=f[now].son[t[j]-'a'];
			dp[j]=(pus&ans[now])?1:0;
			if(dp[j]) tot=j;
			pus=(pus<<1|dp[j])&1023;
		}
		printf("%d\n",tot);
	}
}
posted @ 2021-02-04 20:11  275307894a  阅读(50)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end