游游的选数乘积-2022年携程秋招第四批

 题目分析:末尾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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值