题解:P3883 [JLOI2008] 棋局定式
题意简述
现在有一盘棋局,棋局中的每一步都可以用一个长度不超过
思路讲解
本题只要我们将那些短字符串拼接成若干个长字符串后,那么实际上这就是一个多模式串匹配文本串的题,这种题我们通常使用 AC 自动机来完成,如果我们直接将每个字符压入到 Trie 树上时,那么其字符集大小就变成了
此外,在 AC 自动机查询的时候有一个小剪枝,当遇到了已经被标记过的节点,说明它与它的 fail 树上的儿子均都被标记,那我们直接返回即可,这样做法时间复杂度是线性的,总时间复杂度为
特别提醒
本题中对于
代码时间
#include<bits/stdc++.h>
#define pir pair<int,int>
using namespace std;
typedef long long ll;
const int N=1e6+5;
inline ll read()
{
ll x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int n,m,cnt,idx,ans[N];
bool vis[N];
string a[N],t;
map<char,int> mp;
struct KK{
int son[27];
int fail;
}tr[N];
void ycl(){
mp['K']=++cnt,mp['Q']=++cnt,mp['B']=++cnt,mp['N']=++cnt,mp['R']=++cnt,mp['P']=++cnt;
for(int i='1';i<='8';i++) mp[i]=++cnt;
for(int i='a';i<='h';i++) mp[i]=++cnt;
mp['x']=++cnt;
}
void add(string ss,int id){
int now=0;
for(int i=0;i<(int)ss.size();i++){
int v=tr[now].son[mp[ss[i]]];
if(!v) v=++idx,tr[now].son[mp[ss[i]]]=v;
now=v;
}
ans[id]=now;
}
void build_AC(){
queue<int> q;
for(int i=0;i<26;i++) if(tr[0].son[i]) q.push(tr[0].son[i]);
while(q.size()){
int x=q.front();
q.pop();
for(int i=0;i<26;i++){
if(tr[x].son[i]){
tr[tr[x].son[i]].fail=tr[tr[x].fail].son[i];
q.push(tr[x].son[i]);
}else{
tr[x].son[i]=tr[tr[x].fail].son[i];
}
}
}
}
void ask(string ss){
int now=0;
for(int i=0;i<(int)ss.size();i++){
now=tr[now].son[mp[ss[i]]];
for(int j=now;j;j=tr[j].fail){
if(vis[j]) break;
vis[j]=1;
}
}
}
int main(){
// freopen("1.in","r",stdin);
ycl();
n=read(),m=read();
for(int i=1;i<=n;i++){
int k;
cin>>k;
getline(cin,a[i]);// 碎碎念:因为这个问题我和同学足足调了快一个小时!!!
getline(cin,a[i]);
string ss="";
for(int j=1;j<=k;j++){
cin>>t;
ss+=t;
}
add(ss,i);
}
string ss="";
for(int i=1;i<=m;i++){
cin>>t;
ss+=t;
}
build_AC();
ask(ss);
for(int i=1;i<=n;i++){
if(vis[ans[i]]) cout<<a[i]<<endl;
}
return 0;
}
//code submission time--- 5.12 --- P3883 [JLOI2008] 棋局定式
感谢阅读,谢谢喵\~\~\~