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; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮