题意:
给定一个01串和k,求包含k个1的子串的个数
思路:
用前缀和记录到当前位置的个数,那么就可以知道某个子串的1的个数
我们遍历字符串
对于每个位置i,以他为开头的子串,要求1的个数为k的数量,我们只需要求有多少个值等于sum[i-1]+k就可以了,
枚举肯定不行,因为是前缀和有序,我们二分,两次二分
upper_bound(sum+1,sum+len+1+1,sum[i-1]+k)-lower_bound(sum+1,sum+len+1+1,sum[i-1]+k);
这个式子求得的就是有多少个值等于sum[i-1]+k
还有就是0需要特判
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<set>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e6+5;
char s[maxn];
int sum[maxn];
int main()
{
int k;
scanf("%d%s",&k,s+1);
int len=strlen(s+1);
for(int i=1;i<=len;i++)
{
sum[i]=sum[i-1];
if(s[i]=='1')
sum[i]++;
}
sum[len+1]=sum[len]+1;
int top=sum[len+1];
ll ans=0;
if(!k)
{
ll cnt=0;
for(int i=1;i<=len;i++)
{
if(s[i]=='0')
cnt++;
else
{
ans+=cnt*(cnt+1)/2;
cnt=0;
}
}
if(cnt)
ans+=cnt*(cnt+1)/2;
printf("%lld",ans);
return 0;
}
for(int i=1;i<=len;i++)
{
if(sum[i-1]+k>=top)
break;
ans+=upper_bound(sum+1,sum+len+1+1,sum[i-1]+k)-lower_bound(sum+1,sum+len+1+1,sum[i-1]+k);
}
printf("%lld",ans);
}