最近夜神对二进制很感兴趣,于是他每次看到一串只包含1和0的字符串的时候就会想,这串字符串有多少子串是含有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; }