P4407 [JSOI2009] 电子字典

题目大意

详细题目传送门

给出 \(n\) 个互不相同字典串 \(S_i\)。和 \(m\) 个匹配串 \(Q_i\)。如果有字典串 \(S_i=Q_i\),输出 \(-1\)。三种变换操作:

  1. \(S_{i,j}\) 后添加任意一个字符
  2. 删除 \(S_{i,j}\)
  3. \(S_{i,j}\) 改成任意一个字符。

求每一个匹配串如果只进行 \(1\)操作有几个可以匹配的字典串。

\(n,m\leq 10^4\)

\(|S_i|,|Q_i|\leq 20\)

所有字符串都只有小写字母。

思路

考虑字典树。

发现时间复杂度猜一下是 \(O(26m|Q|)\) 的。其实发现哈希应该就能做,但是作者考场上没有写出来哈希,于是在这里补一个字典树做法。

先将所有字典串插入字典树,并记录结尾结点。对于每一个匹配串考虑深搜,用 \(f(u,l,c)\) 表示当前考虑到了字典树的 \(u\) 节点,是第 \(l\) 位,\(c\) 表示是否已经修改过。

如果已经修改过就一直到尾去记录是不是一个字典串。

之后对于三种操作:

添加任意一个字符就是对于 \(u\),进入到字符 \(x\) 中也就是搜索 \(f(t_{u,x},l,\text{true})\)。修改操作就是 \(f(t_{u,x},l+1,\text{true})\)。如果还能删就到 \(f_{t_{u,Q_{i,l}},l+1,\text{true}}\)。当然也可以选择这一位不修改。

代码

#include <bits/stdc++.h>
#define endl "\n"
using namespace std;
typedef long long ll;
const ll MAXN=1e5+5;
ll trie[MAXN*20][26],tot,ed[MAXN*20];
void insert(string s){
    ll u=0;
    for(auto c:s){
        int x=c-'a';
        if(!trie[u][x]){
            trie[u][x]=++tot;
        }
        u=trie[u][x];
    }
    ed[u]=1;
}
string s;
bool vis[MAXN];
ll vu[MAXN],ans;
set<string>se;
void dfs(ll u,ll len,bool change){
    if(len==s.size()&&ed[u]){
        if(change&&!vis[u]){
            vu[++ans]=u;
            vis[u]=true;
        }
        return;
    }
    if(len>=s.size()){
        if(!change){
            for(int i=0;i<26;++i){
                if(!trie[u][i]){continue;}
                dfs(trie[u][i],len,true);
            }
        }
        return;
    }
    ll x=s[len]-'a';
    if(trie[u][x]){
        dfs(trie[u][x],len+1,change);
    }
    if(!change){
        dfs(u,len+1,true);
        for(int i=0;i<26;++i){
            if(!trie[u][i]){continue;}
            dfs(trie[u][i],len,true);
            dfs(trie[u][i],len+1,true);
        }
    }
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    ll n,Q;
    cin>>n>>Q;
    for(int i=1;i<=n;++i){
        cin>>s;
        se.insert(s);
        insert(s);
    }
    while(Q--){
        cin>>s;
        if(se.count(s)){
            cout<<-1<<endl;
            continue;
        }
        ans=0;
        dfs(0,0,false);
        if(ans<0){
            cout<<-1<<endl;
            continue;
        }
        cout<<ans<<endl;
        while(ans){
            vis[vu[ans]]=false;
            ans--;
        }
    }
    return 0;
}
posted @ 2024-12-19 21:21  tanghg  阅读(3)  评论(0编辑  收藏  举报