因为结尾0的个数取决于有多少对 ( 2 , 5 ) (2,5) (2,5) 相乘,那么对于下面例题,解题思路为:
1、将每个数字中的2和5剥离出来,然后用两个数组进行记录,然后其子数 ( 2 , 5 ) (2,5) (2,5)组成对至少为k个。
2、遍历每一个子数组然后计算:会发现超时:
下面公式推导一下:
t
o
t
l
e
2
−
t
w
o
>
=
k
、
t
o
t
l
e
5
−
f
i
v
e
>
=
k
由于
t
w
o
=
f
2
[
j
]
−
f
2
[
i
]
;
这里的
f
为数组
2
剥离的前缀和
由于
f
i
v
e
=
f
5
[
j
]
−
f
5
[
i
]
;
上述
i
,
j
为子数组
(
i
,
j
−
1
)
。因此我们固定
i
,由于前缀和是递增的,因此可以使用二分,找到右边界。
推到出:
t
o
t
l
e
−
(
f
[
j
]
−
f
[
i
]
)
>
=
k
;
t
o
t
l
e
+
f
[
i
]
−
k
>
=
f
[
j
]
;
totle2-two>=k、totle5-five>=k\\ 由于two = f2[j]-f2[i];这里的f为数组2剥离的前缀和\\ 由于five = f5[j]-f5[i];\\ 上述i,j 为子数组(i,j-1)。因此我们固定i,由于前缀和是递增的,因此可以使用二分,找到右边界。\\ 推到出: totle-(f[j]-f[i])>=k;\\ totle+f[i]-k>=f[j];
totle2−two>=k、totle5−five>=k由于two=f2[j]−f2[i];这里的f为数组2剥离的前缀和由于five=f5[j]−f5[i];上述i,j为子数组(i,j−1)。因此我们固定i,由于前缀和是递增的,因此可以使用二分,找到右边界。推到出:totle−(f[j]−f[i])>=k;totle+f[i]−k>=f[j];
那么讨论一下边界问题:
二分 f [ j ] f[j] f[j]返回的是第一个大于 f [ j ] f[j] f[j]值的位置,但是这时就不符合 t o t l e + f [ i ] − k > = f [ j ] totle+f[i]-k>=f[j] totle+f[i]−k>=f[j]了,因此减去1,此时是刚好的。
#include <iostream>
#include <set>
#include <vector>
using namespace std;
// 剥离n中存在几个base的因子。如果是2,和5的话,
// 就是base中存在多少个2相乘和多少个5相乘
int factor(int n, int base){
int ans = 0;
while (n and !(n%base)) {
n/=base;
ans++;
}
return ans;
}
int base_right(const vector<int>& vec, int value){
int left = 0;
int right = vec.size()-1;
int res = -1;
while (left<=right) {
int mid = left+((right-left)>>1);
if(vec[mid]>value){
res = mid;
right = mid-1;
}else{
left = mid+1;
}
}
if(res == -1) return vec.size();
return res;
}
int main() {
int n, k;
cin>>n>>k;
vector<int> vec(n);
vector<int> factor2(n+1);
vector<int> factor5(n+1);
int totle2 = 0;
int totle5 = 0;
for(int i=0;i<n;i++){
cin>>vec[i];
int x = factor(vec[i], 2);
factor2[i+1] = factor2[i]+x;
totle2+=x;
x = factor(vec[i], 5);
factor5[i+1] = factor5[i]+x;
totle5+=x;
}
// 这里进行二分查找加速
long long ans = 0;
for(int i=0;i<n;i++){ // 以每个点为起点
int val2 = totle2+factor2[i]-k;
int val5 = totle5+factor5[i]-k;
int pos2 = base_right(factor2, val2);
int pos5 = base_right(factor5, val5);
if(min(pos2, pos5)-i-1<=0) continue;
ans+=min(pos2, pos5)-i-1;
}
cout<<ans<<endl;
return 0;
}