链接:https://www.nowcoder.com/questionTerminal/6f0d16fc06274f44af8913d182668037
来源:牛客网
小明最近在做病毒自动检测,他发现,在某些library 的代码段的二进制表示中,如果包含子串并且恰好有k个1,就有可能有潜在的病毒。library的二进制表示可能很大,并且子串可能很多,人工分析不可能,于是他想写个程序来先算算到底有多少个子串满足条件。如果子串内容相同,但是开始或者结束位置不一样,则被认为是不同的子串。
注:子串一定是连续的。例如"010"有6个子串,分别是 "0, "1", "0", "01", "10", "010"
输入描述:
第一行是一个整数k,表示子串中有k个1就有可能是病毒。其中 0 <= k <= 1 000 000 第二行是一个字符串,就是library的代码部分的二进制表示。字符串长度 <= 1 000 000。并且字符串中只包含"0"或"1".
输出描述:
输出一个整数,所有满足只包含k个1的子串的个数。示例1
输入
1 1010输出
6说明
满足条件的子串有:"1", "1", "10", "01", "10", "010".示例2
输入
2 01010输出
4说明
满足条件的子串有: "101", "0101", "1010", "01010".示例3
输入
100 01010输出
0
这道题太难了,目前只想到前缀和加二分搜索,只过了94%case。
#include<stdio.h>
#include<iostream>
#include<string>
#include<vector>
using namespace std;
string s;
int k;
vector<int> record;
int n;
int binary_search(int l,int r,int key){
while(l<=r){
int mid=(l+r)/2;
if(record[mid]==key){
int count=1;
for(int i=mid+1;i<=r;i++){
if(record[i]==key){
count++;
}
else{
break;
}
}
for(int i=mid-1;i>=l;i--){
if(record[i]==key){
count++;
}
else{
break;
}
}
return count;
}
else if(record[mid]>key){
r=mid-1;
}
else{
l=mid+1;
}
}
return 0;
}
int main(){
cin>>k;
cin>>s;
n=s.size();
record.resize(n);
int sum=0;
for(int i=0;i<n;i++){
if(s[i]=='1')
sum++;
record[i]=sum;
}
int ans=0;
for(int i=-1;i<n-1;i++){
int num;
if(i<0)
num=record[n-1];
else
num=record[n-1]-record[i];
if(num<k)
break;
/*
for(int j=i+1;j<n;j++){
if(i<0)
num=record[j];
else
num=record[j]-record[i];
if(num==k){
ans++;
}
if(num>k)
break;
}
*/
ans+=binary_search(i+1,n-1,i>=0?record[i]+k:k);
}
printf("%d\n",ans);
}