题目分析:末尾0的个数=max(a,b) ,其中因子2个数a,因子5个数b。如果满足条件,两个数乘积,也是就是因子2的个数和和因子5的个数和均大于等于X。
先考虑另一个相似问题,在一个数组a中,选出两个数的和大于等于X,满足条件的选取方式有多少种。此问题常见的做法是采用双指针,(1)先对数组升序排序,(2)设定两个指针初值为L=1,R=n,
L=1,R=n,
while(L<R)
{
while(a[L]+a[R]<X)
那么必须让L++,直到满足条件a[L]+a[R]>=X;
这样对于a[R]来说,a[L,R-1]都满足条件
ans+=R-L+1;
}
回到本问题,可以先把每个数字的因子2和因子5个数求出来,再对因子2进行排序。利用上述算法可以锁定满足条件的区间【L,R】,当然,这个区间里面只有2的个数满足条件,5的个数我们使用一个计数数组来保存,因为数字均小于10的9次幂,所以每个数字2的个数和5的个数均比较少。这样在统计的时候,对整个计数数组(记录5)遍历次数可以忽略不记。整个算法复杂度为O(nlogn)。
#include <bits/stdc++.h>
using namespace std;
struct node
{
int er,wu;
bool operator<(const node B)const/**< 按2个数升序 */
{
return er<B.er;
}
} a[100005];
int t[1005];/**< 计数数组,如数据量大使用树状数组 */
long long ans=0;
int main()
{
int n,x,c,i;
cin>>n>>x;
for(i=1; i<=n; i++)
{
cin>>c;
while(c&&c%2==0)
c/=2,a[i].er++;
while(c&&c%5==0)
c/=5,a[i].wu++;
}
sort(a+1,a+n+1);
int L=1,R=n+1;/**< 确定满足条件区间,双指针向中间靠拢,R=n+1为了下面循环好处理 */
for(i=1; i<=n; i++) /**< 统计包含多少个5的数量 */
t[a[i].wu]++;
while(L<R)
{
R--;
t[a[R].wu]--;/**< 把自身5排除掉 */
while(L<R&&a[L].er+a[R].er<x)
t[a[L].wu]--,L++;/**< 不满足条件的a[L].wu排除掉 */
for(i=max(0,x-a[R].wu); i<20; i++) /**< 统计下[L,R-1]区间满足条件的个数 */
ans+=t[i];
}
cout<<ans;
return 0;
}