牛客小白月赛73 D-Kevin喜欢零(简单版本)(前缀积+二分)

链接:登录—专业IT笔试面试备考平台_牛客网

本题分为简单版本和困难版本,二者唯一的区别是:简单版本有序列 a 所有元素乘积 ≤1018的限制,困难版本没有。

氧气少年最近喜欢上了零。

给出一个长度为 n(1≤n≤2⋅105)的序列 a(1≤ai​≤109),并且保证序列 a 所有元素乘积 ≤1018,求这个序列中满足如下条件的连续子段 [al…ar] 的数量:

  • 令 x=al⋅al+1⋅al+2…ar,那么 xxx 的末尾恰好有 k(0≤k≤109) 个零。

输入描述:

第一行包含一个整数 T(1≤T≤105),表示测试用例的组数。

对于每组测试用例:

第一行包含两个整数 n(1≤n≤2⋅105) 和 k(0≤k≤109),表示序列的长度和题目中提到的后导零的数量;

第二行包含 n 个整数 a1…an (1≤ai≤109),表示该序列。

保证对于所有的测试用例,n 的总和不超过 2⋅105。

输出描述:

对于每组测试用例:

仅输出一行,包含一个整数,表示答案。

示例1

输入

2
5 3
125 1 8 1 1
1 0
6

输出

3
1

比赛的时候死活想不出来二分的来找,一直超时。。。。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[200001];
ll check(ll a)
{
	ll res=0;
	do{
		if(a%10==0)
		res++;
		else
		break;
		a/=10;
	}while(a);
	return res;
}
int main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	ll t;
	cin>>t;
	while(t--)
	{
		ll n,k;
		cin>>n>>k;
		a[0]=1;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			a[i]*=a[i-1];
		}
		ll ans=0;
		for(int i=1;i<=n;i++)
		{
			ll tl=i,tr=n;
			while(tl<tr)
			{
				int mid=tl+tr>>1;
				if(check(a[mid]/a[i-1])>=k) tr=mid;
				else tl=mid+1;
			}
			ll ans2=tl;
			tl=i,tr=n;
			while(tl<tr)
			{
				ll mid=tl+tr+1>>1;
				if(check(a[mid]/a[i-1])<=k) tl=mid;
				else tr=mid-1;
			}
			if(check(a[ans2]/a[i-1])==k)
			ans+=tl-ans2+1;
		}
		cout<<ans<<endl;
	}
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值