其中字符串长度范围为2<=K<=|S|<=5e5
题目如上,要求以c1开头,c2结尾的长度>=k的所有子串的个数,很明显暴力会超时(O(n^2))
假设c1=a , c2=b;
故可采用贡献法,从前往后枚举,枚举到每一个b(假设下标为i)时,求出s[i]对答案的贡献,由于字符串长度大于等于k,所以只需要知道从i-k+1及其之前a的个数sum[i-k+1],那么sum数组该如何更新呢?可以采用递推的方式,如下:
枚举到每一个位置时,更新 sum[i]=sum[i-1]+(s[i]==a);
设置一个变量ans记录答案
枚举到每一个b时,ans+=sum[max(0,i-k+1)],这里用max(0,i-k+1)是为了防止数组下标越界
此时题目就分析完成了!可以开始写代码了
C++代码如下:
#include<iostream>
#include<cstring>
using namespace std;
const int N=500010;
char s[N];
int sum[N];
char a,b;
int k;
int main(){
cin>>k;
scanf("%s",s+1);
cin>>a>>b;
int n=strlen(s+1);
long long ans=0;
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+(s[i]==a);
if(s[i]==b)ans+=sum[max(0,i-k+1)];
}
cout<<ans<<endl;
return 0;
}