-
[1665] 夜神的思考
- 时间限制: 1000 ms 内存限制: 65535 K
- 问题描述
-
最近夜神对二进制很感兴趣,于是他每次看到一串只包含1和0的字符串的时候就会想,这串字符串有多少子串是含有k个1的呢。
你们能不能快速的解决这个问题。
- 输入
-
输入数据包含多组,先输入k ( 0 =< k <= 10^6 ) , 再在接下来的一行输入一串只包含1和0的字符串,字符串的长度不超过10^6.
- 输出
-
输出一个整数,这个整数就是这串字符串有多少子串是含有k个1的。
- 样例输入
-
1 1010 2 01010 100 01010
- 样例输出
-
6 4 0
- 提示
-
第一串字符串中,“1”,“1”,“10”,“01”,“10”,“010”都只含有一个1,所以答案输出6 第二串字符串中,"101", "0101", "1010", "01010",都含有2个1,所以答案为4。
做法:total的前n-1个下标记录每一个1的位置,值记录对应左边0的个数(最后第n个位置再多记录一个末尾的0个数)。
例如:2 00100010 此时k=2,total={1,1,1}代表第一个1左边两个0,第二个1左边三个0,第三个1代表末尾一个0
然后分类讨论,k=0和k!=0
①、k=0比较简单,但是被坑了好多次WA,计算公式是∑(1~当前位置0的个数),例如上题若k=0,那么就是(1+2)+(1+2+3)+(1)=10,此前一直写成2^n-1让我WA了好几次....
②、k!=0,那么每次的Sum=(total[l]+1)*(total[r]+1)(其中r-l+1即距离应恒为k)
代码:
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef __int64 LL;
LL zxc(LL b)
{
LL r=0;
for (LL i=1; i<=b; i++)
{
r=r+i;
}
return r;
}
char cc[1000009];
LL total[1000009];
int main (void)
{
LL k,i,j,sum,l,r;
while (~scanf("%I64d",&k))
{
memset(cc,0,sizeof(cc));
memset(total,0,sizeof(total));
scanf("%s",cc);
LL len=strlen(cc);
LL ans=0;
LL cnt=0;
LL sum=0;
for (i=0; i<len; i++)
{
if(cc[i]=='1')
{
total[cnt++]=sum;
sum=0;
}
else
{
sum++;
}
}
total[cnt]=sum;//记录末尾0个数
if(k==0)//k==0的情况
{
for (i=0; i<=cnt; i++)
{
ans=ans+zxc(total[i]);
}
printf("%I64d\n",ans);
continue;
}
l=0;
r=k;//定义两个下标
for (i=0; r<=cnt; i++)
{
ans=ans+(total[l]+1)*(total[r]+1);
l++;
r++;
}
printf("%I64d\n",ans);
}
return 0;
}