Ac自动机+状压+dp TLE求助
查看原帖
Ac自动机+状压+dp TLE求助
220824
yyz1005楼主2022/7/7 11:45

Rt,80pts

p[i]p[i]:如 p[i]=16(10000)p[i]=16(10000) 则第 ii 项到第 i+41i+4-1 是一个单词

dp[i]为从i(下标从0开始)开始可以表示的最大区域(dp[2]=15即从下标为2个单词最远可以理解到第15个单词)

dp[x]=max(i,dp[i+j](p[i] and (1<<j)=1 ))dp[x]=\max(i,dp[i+j](\text{p[i] and (1<<j)=1 }))

#include<bits/stdc++.h>
using namespace std;
int n;
char s[30][30],t[2000010];
int trie[30*30*4][30];
int fail[30*30*4];
int ncnt[30*30*4];
int cnt = 0;
int remean[160*100*4];
void inser(int nums){
	int id = 0;
	int leng = strlen(s[nums]);
	for(int i = 0; i < leng; i++){
		if(trie[id][s[nums][i]-'a']) id = trie[id][s[nums][i]-'a'];
		else {
			cnt++;
			trie[id][s[nums][i]-'a'] = cnt;
			id = cnt;
		}
	}
	ncnt[id]++;
	remean[id] = nums;
}
void buildfail(){
	queue<int> unq;
	fail[0] = 0;
	for(int i = 0; i < 26; i++){
		if(trie[0][i]){
			unq.push(trie[0][i]);
			fail[trie[0][i]] = 0;
		} 
	}
	while(!unq.empty()){
		int fir = unq.front();
		unq.pop();
		for(int i = 0 ; i < 26; i++){
			if(trie[fir][i]){
				fail[trie[fir][i]] = trie[fail[fir]][i];
				unq.push(trie[fir][i]);
			} else {
				trie[fir][i] = trie[fail[fir]][i];
			}
		}
	}
	
}
int p[2000010];
int dp[2000010];
void query(){
	int id = 0,leng = strlen(t);
	for(int i = 0; i < leng; i++){
		id = trie[id][t[i]-'a'];
		for(int j = id; j; j = fail[j]){
			if(ncnt[j]!=0){
				p[i-strlen(s[remean[j]])+1]|=(1<<(strlen(s[remean[j]])));
			}
		}
	}
	dp[leng] = leng;
	for(int i = leng-1; i >= 0; i--){
		dp[i] = i;
		for(int j = 1; j <= 20; j++){
			if(p[i]&(1<<j)) dp[i] = max(dp[i],dp[i+j]);
		}
	}
	printf("%d\n",dp[0]);
}
int m;
int main(){
	cin >> n >> m;
	for(int i = 1; i <= n; i++){
		scanf("%s", s[i]);
		inser(i);
	}
	buildfail();
	while(m--){
		memset(p,0,sizeof(p));
		memset(dp,0,sizeof(dp));
		scanf("%s", t);
		query();
	}
	return 0;
}
2022/7/7 11:45
加载中...