原题链接:Kevin喜欢零(简单版本) (nowcoder.com)
思路:保证了乘积的范围不超过unsigned long long,所以可以利用前缀积,快速的判断一段区间的乘积,有可能找不到后缀是k的情况,如果找到就可以用二分法求出做左、右端点。可以先枚举区间左端点,右端点固定为n,这样寻找,就会找到所有的连续子段,然后求出区间,求出区间长度就是个数,然后相加就是总的个数
#include<iostream>
using namespace std;
typedef unsigned long long ull;
const int N=2*1e5+10;
ull a[N],s[N]={1},n,k;
ull check(ull p)//前缀积
{
ull res=0;
while(p&&p%10==0)
{
res++;
p/=10;
}
return res;
}
int main()
{
int t;
cin>>t;
while(t--)//格式输入
{
ull res=0;
cin>>n>>k;//格式输入
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
s[i]=s[i-1]*a[i];//初始化前缀积数组
}
for(int i=1;i<=n;i++)
{
int l1=i,r1=n;
while(l1<r1)//左端点
{
int mid=l1+r1>>1;
if(check(s[mid]/s[i-1])<k)l1=mid+1;
else r1=mid;
}
int x=l1;
int l2=i,r2=n;
while(l2<r2)//右端点
{
int mid=l2+r2+1>>1;
if(check(s[mid]/s[i-1])>k)r2=mid-1;
else l2=mid;
}
int y=l2;
if(check(s[y]/s[i-1])==k)//如果右端点满足后导0等于k,那就说明这个区间成立找到了这段区间//如果不成立就说明没有后导0等于k的区间,二分只会找到最接近的一个数,不会存在找不到的情况
res+=y-x+1;//因为每次都从i为左端点,就可以满足所有情况,个数就是区间长度
}
cout<<res<<endl;
}
return 0;
}