提供一种序列分治的思路。还算比较general。

首先我们需要知道,0的个数取决于的个数的最小值。启示我们预处理出每一个数字中5的个数和2的个数。

根据的个数来进行排序,然后我们定义如下分治函数,会将区间分割为.那么答案就拆分为计算左右区间之间跨区间的个数,然后分治计算

关键是如何跨区间,由于我们已经对的个数来排序了,那么对于右区间,我们可以从往右遍历,然后对于左区间,从开始从右往左遍历。

由于有序性质,我们可以枚举右区间,这个时候如果的2个数与的2个数大于等于x,那么可以减1,并且这是一个循环的过程,尝试找到更多的符合条件的元素,而且指针不会回退。

这样我们只需要知道之间5的个数符合的元素。由于中5的幂次很有限,30个左右,所以我们可以直接统计个数,然后暴力枚举计数。

更多序列分治题目,可见:https://www.cnblogs.com/MnZnOIerLzy/p/17812919.html

注意python得用pypy3.

import sys

# 输入加速
input = sys.stdin.readline

if __name__ == '__main__':
    n, x = map(int, input().split())
    arr = list(map(int, input().split()))
    """
        预处理出,每一个数2和5的个数
        5 * 5 * 2
        2 * 2 * 2 * 2 * 5
        选两个数,那么就是经典枚举右维护左
        cur5 cur2  需要找同时满足 大于等于 x - cur5   x - cur2 的个数
        可以排序
        pre5 + 1 >= x - cur5 + 1
    """
    lst = []
    for i in range(n):
        xx = arr[i]
        cur5 = cur2 = 0
        while xx % 5 == 0:
            xx //= 5
            cur5 += 1
        while xx % 2 == 0:
            xx //= 2
            cur2 += 1
        lst.append((cur2, cur5))
    lst.sort()


    # 第一维度双指针,第二维度暴力维护5的个数 题目所给例子的2和5个数情况:[(0, 0), (0, 1), (1, 0), (1, 2), (4, 1)]
    def dfs(l, r) -> int:
        if l == r:
            return 0
        mid = (l + r) // 2
        cnt = 0
        j = mid
        mp5 = [0] * 31
        for i in range(mid + 1, r + 1):
            while j >= l and lst[j][0] + lst[i][0] >= x:
                mp5[lst[j][1]] += 1
                j -= 1
            lb = max(0, x - lst[i][1])
            for k in range(lb, 31):
                cnt += mp5[k]

        return cnt + dfs(l, mid) + dfs(mid + 1, r)


    print(dfs(0, n - 1))