返回顶部

Educational Codeforces Round 48 (Rated for Div. 2) B. Segment Occurrences (二分查找)

  • 题意:给你两个字符串\(a\)\(b\),有\(q\)个询问,每次给你一个区间\([l,r]\),问你在\([a_l,...,a_r]\)中,子串\(b\)出现了多少次.

  • 题解:我们可以先预处理出所有\(b\)\(a\)中的起始和末尾位置,用两个数组分别存他们,其中存末尾位置的时候要取负,方便后面二分查找,然后每次询问的时候,我们可以二分查找出\(l\)右边的第一个子串序号,再二分查找出\(r\)左边的第一个子串序号,二者取差加一即是答案,注意出现负数的情况.

  • 代码:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
     
     
     
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    	int n,m,q;
    	string s,t;
    	cin>>n>>m>>q;
    	vector<int> l,r;
    	cin>>s>>t;
    	s=" "+s;
    	t=" "+t;
     
    	rep(i,1,n){
    		if(s[i]==t[1]){
    			int j=i;
    			int k=1;
    			while(s[j]==t[k] && j<=n && k<=m){
    				j++;
    				k++;
    			}
    			if(k-1==m){
    				l.pb(i);
    				r.pb(-(i+m-1));
    			}
    		}
    	}
     
    	sort(l.begin(),l.end());
    	sort(r.begin(),r.end());
    	int len=(int)r.size();
    	len--;
     
    	while(q--){
    		int l_,r_;
    		cin>>l_>>r_;
    		auto x1=lower_bound(l.begin(),l.end(),l_);
    		auto x2=lower_bound(r.begin(),r.end(),-r_);
    		if(x1==l.end() || x2==r.end()){
    			cout<<0<<'\n';
    			continue;
    		}
    		int l1=x1-l.begin();
    		int r1=x2-r.begin();
    		r1=len-r1;
    		cout<<max(0,r1-l1+1)<<'\n';
    	}
    	
        return 0;
    }
    
posted @ 2021-04-08 23:19  _Kolibri  阅读(41)  评论(0)    收藏  举报