小白赛73 DE
链接:https://ac.nowcoder.com/acm/contest/57683/E
来源:牛客网
首先我们得知道0怎么来的,显然根据质因数的原理,0只有从2和5两个质数相乘而来,那么我们只需要记录每个数字的2和5的数量,并且记录2的个数和5的个数的前缀和,二者取最小即为0的个数

然后就是枚举加二分了,枚举区间左界l,二分查找有界,找到最小的和最大的右界r1和r2使得l~r1和l~r2刚好有k个0,答案就加上r2-r1+1
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;  
long long n,p2[200005],p5[200005];
long long c[200005];
long long a[200005],t,k;
int main()
{
    cin >> t;
    while (t--)
    {
         
       cin >> n >>k;
        int cnt2=0,cnt5=0;
        p2[0]=0;
        p5[0]=0;
        for(int i =1 ; i<= n ;i++)
        {
            cin >> a[i];
            int c2=0,c5 =0;
            int t = a[i];
            while(t%2==0)
            {
                c2++;
                t/=2;
            }
             t = a[i];
             while(t%5==0)
            {
                c5++;
                t/=5;
            }
            p2[i]=p2[i-1]+c2;
            p5[i]=p5[i-1]+c5;
         
        }
       
        long long ans = 0;
  
       for(int l = 1 ; l<= n ;l++)//枚举左界
        {
          int l1 =l ,r =n;
           while(l1<r)//找符合要求的下界(最小的右界)
           {
               int mid =(l1+r)/2;
             long long t =min((p2[mid]-p2[l-1]),(p5[mid]-p5[l-1]));
               if(t >= k) r= mid ;
               else l1 = mid+1;
           }
              long long t =min((p2[l1]-p2[l-1]),(p5[l1]-p5[l-1]));
           if(t!=k) continue;
          int l2 =l, r2 = n;
           while(l2<r2)//上界
           {
               int mid = (l2+r2+1)/2;
              long long t =min((p2[mid]-p2[l-1]),(p5[mid]-p5[l-1]));
               if(t > k) r2= mid-1 ;
               else l2 = mid;
           }
           t =min((p2[l2]-p2[l-1]),(p5[l2]-p5[l-1]));
           if(t!=k)continue;
           ans+=l2-l1+1;
        }
        cout<<ans<<endl;
    }
    return 0;
}