NOJ——1665夜神的思考(YY+组合问题+分类讨论)

  • [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;
}
posted @ 2016-03-29 09:41  Blackops  阅读(308)  评论(0编辑  收藏  举报