CF914F Substrings in a String 题解

CF914F Substrings in a String

题意:给定一个长为 \(n\) 的文本串,有 \(m\) 次操作,每次可以修改文本串某一位的字符,也可以给出一个模式串 \(s\) 询问文本串的区间 \([l,r]\) 内该模式串出现了几次。\(n,m,\sum |s| \le 10^5\)。

对每一个字母开一个 bitset 储存对应字母出现的位置。

for(int i=1;i<=n;i++){
    a[t[i]-'a'].set(i);
}

修改操作是简单的。回答询问时,开一个 bitset 表示文本串的哪些位置可以作为匹配的起点,初始全部赋为 \(1\)。遍历模式串 \(s\) 的每一位,做一个这样的操作。

for(int i=0;i<s.size();i++){
    ans&=a[s[i]-'a']>>i;
}

表示按位与上所有后面第 \(i\) 个位置是 \(s_i\) 的文本串位置。比如说先与上所有是 \(s_0\) 的位置表示这些点是合法启始点,再与上下一个位置是 \(s_1\) 的点,以此类推,就能得到所有合法的匹配启始点位置。

但是还要区间查询,那就要求起点 \(k \ge l\),且 \(k \le r-|s|+1\)。

(ans>>l).count()-(ans>>r-s.size()+2).count()

可以这样操作来得到,大于等于 \(l\) 的起点数减去大于等于 \(r-|s|+2\) 的起点数。

时间复杂度 \(O(\frac{qn}{\omega})\)。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int n,m;
const int N = 1e5+10;
bitset<N>ans,a[26];
string s,t;
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>t;
    n=t.size();
    t=' '+t;
    for(int i=1;i<=n;i++){
        a[t[i]-'a'].set(i);
    }
    cin>>m;
    while(m--){
        int op,x;
        char c;
        cin>>op;
        if(op==1){
            cin>>x>>c;
            a[t[x]-'a'].reset(x);
            t[x]=c;
            a[c-'a'].set(x);
        }else{
            int l,r;
            cin>>l>>r;
            cin>>s;
            if(s.size()>r-l+1){
				cout<<"0"<<endl;
				continue;
			}
            ans.set();
            for(int i=0;i<s.size();i++){
                ans&=a[s[i]-'a']>>i;
            }
            cout<<(ans>>l).count()-(ans>>r-s.size()+2).count()<<endl;
        }
    }
    return 0;
}
posted @ 2026-09-15 20:57  farenara_sayowell  阅读(7)  评论(0)    收藏  举报