2024杭电多校2——1011在A里面找有C的B

补题链接

在这里插入图片描述
在这里插入图片描述
本题需要的前置知识:hash/kmp+ACAM,解法很简单,没有什么好补充的,不过可以学习一下std的写法,构建fail树,再跑一遍dfs累积答案,这样的做法比较高效,不过我写kmp+ac自动机会TLE,估计可能是STL的锅,hash就快很多

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using i128 = __int128;
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);

const int maxn = 1e6+10;
int tr[maxn][26], cnt;
int exist[maxn];
int fail[maxn];
int sum[maxn];
vector<int>g[maxn];
struct trie{
    inline int insert(const string &s){
        int p = 0;
        for(char ch:s){//从索引0开始到结尾
            int c = ch-'a';//只能处理全是小写字母,要普适需修改
            if(!tr[p][c]) tr[p][c] = ++cnt;
            p = tr[p][c];
        }
        return p;
    }
    inline void build() {
        queue<int> q;
        for (int i = 0; i < 26; i++){
            if(tr[0][i]) q.push(tr[0][i]);
        }
        while(!q.empty()){
            int u = q.front();
            q.pop();
            for (int i = 0; i < 26; i++) {
                if(tr[u][i]){
                fail[tr[u][i]] = tr[fail[u]][i];//儿子存在,建回跳边
                q.push(tr[u][i]);
                }else tr[u][i] = tr[fail[u]][i];//建转移边
            }
        }
        for(int i = 1;i<=cnt;++i){
            g[fail[i]].push_back(i);
        }
    }
};

inline void dfs(int x){
    for(auto y:g[x]){
        dfs(y);
        sum[x]+=sum[y];
    }
}

const int mod1 = 1e9+7,mod2 = 998244353;
const int b1 = 37,b2 = 233;
int p1[maxn],p2[maxn];
int h1[maxn],h2[maxn];

inline int get1(int l,int r){
    return (1LL*h1[r]-1LL*h1[l-1]*p1[r-l+1]%mod1+mod1)%mod1;
}
inline int get2(int l,int r){
    return (1LL*h2[r]-1LL*h2[l-1]*p2[r-l+1]%mod2+mod2)%mod2;
}

int n;
inline void solve(){
    cin>>n;
    vector<pair<string,string>> a(n);
    string A,C;
    cin>>A>>C;

    int r1 = 0,r2 = 0;
    for(int i = 0;i<C.size();++i){
        r1 = (1LL*r1*b1%mod1+C[i]-'a'+1LL)%mod1;
        r2 = (1LL*r2*b2%mod2+C[i]-'a'+1LL)%mod2;
    }
    pair<int,int> c = {r1,r2};
    trie t;
    for(int i = 0;i<n;++i){
        cin>>a[i].first>>a[i].second;
        h1[0] = h2[0] = 0;
        for(int j = 1;j<=a[i].second.size();++j){//索引从0开始要往后移一格
            h1[j] = (1ll * h1[j - 1] * b1 % mod1 + a[i].second[j-1] - 'a' + 1LL) % mod1;
            h2[j] = (1ll * h2[j - 1] * b2 % mod2 + a[i].second[j-1] - 'a' + 1LL) % mod2;
        }
        bool flag = 0;
        for(int j = 1;j+C.size()-1<=a[i].second.size();++j){
            int l1 = get1(j,j+C.size()-1),l2 = get2(j,j+C.size()-1);
            pair<int,int> tmp = {l1,l2};
            if(tmp==c){
                flag = 1;
                break;
            }
        }
        if(flag){
            exist[i] = t.insert(a[i].first);//每个点节点位置的编号
        }
    }
    t.build();
    int u = 0;
    for(auto i:A){
        u = tr[u][i-'a'];
        sum[u]++;
    }
    dfs(0);
    for (int i = 0;i<n ;i++) {
      if (exist[i] && sum[exist[i]] > 0) {
        cout<<i+1<<" ";
      }
    }
    cout<<"\n";
    for(int i = 0;i<n;++i) exist[i] = 0;
    for(int i = 0;i<=cnt;++i){
        sum[i]=0;
        fail[i]=0;
        memset(tr[i],0,sizeof tr[i]);
        g[i].clear();
    }
    cnt=0;
}

signed main(){
    ios;
    p1[0]=p2[0]=1;
    for(int i = 1;i<=1e5+10;++i){
        p1[i] = 1LL*p1[i-1]*b1%mod1;
        p2[i] = 1LL*p2[i-1]*b2%mod2;
    }
    int t;cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值