ABC400C题解

这题卡精度!!!!卡精度!!!!卡精度!!!!卡精度!!!!

我告诉你,C 题比 D 题难很多。

首先可以想到如下程序:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
unordered_map<int,int>mp;
signed main()
{
    int n;
    int num = 0;
    scanf("%lld",&n);
    int t = log2(n);
    for(int i = 1;i<=t;i++)
    {
        int tt = sqrt(n/(1ll<<i));
        for(int j = 1;j<=tt;j++)
        {
            if(!mp.count((1ll<<i)*j*j))
            {
                num++;
                mp[(1ll<<i)*j*j] = 1;
            }
        }
    }
    printf("%lld",num);
    return 0;
}

但是……会 TLE,考虑优化掉找 \(b\) 的那一个循环。
如何优化?如果我们直接让 num+=tt,会出现重复现象,那如何解决这个问题?
考虑任何一个数的质因数分解形式:

\[x = \prod_{i = 1}^n p_i^{k_i} \]

\[x = p_1^{k_1}\prod_{i = 2}^n p_i^{k_i} \]

你会发现 \(p_1\) 就是 \(2\),所以 \(p_1^{k_1}\) 就是“好的数”的形式的第一项,然后我们再次转化:

\[x = p_1^{k_1}\left(\prod_{i = 2}^n p_i^{\frac{\lfloor k_i \rfloor}{2}}\right)^2 \]

所以说,我们如果枚举“好的数”的第一项,那么第二项的开根号一定是一个奇数,但是在实现程序的时候你会发现第二项的开根号也有可能是一个偶数,那是因为第二项中依然包含 \(2\) 的倍数,也就是说不是一个质因数分解的形式,所以说偶数的情况不用管,因为还可以通过从第二项中把所有 \(2\) 的倍数的数包含的 \(2\) 次幂因子挪到第一项中,所以说后面一定会遍历到,所以代码就出现了:

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
    int n;
    scanf("%lld",&n);
    int t = 63-__builtin_clzll(n);//可以自己查一下c++的__bultin函数,超好用,这个是求log2(n)的
    int num = 0;
    for(int i = 1;i<=t;i++)
    {
        int ii = (1ll<<i);
        int ss = sqrt(n/ii);
        num+=(ss+1>>1);
    }
    printf("%lld",num);
    return 0;
}

当然了,前面说了这个题卡爆精度,所以这份代码 WA 了 \(4\) 个测试点……
怎么办呢?
二分呗!

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
    int n;
    scanf("%lld",&n);
    int t = 63-__builtin_clzll(n);
    int num = 0;
    for(int i = 1;i<=t;i++)
    {
        int ii = (1ll<<i);
        int ss = sqrt(n/ii);
        int l = 1,r = ss+10;//这个+10是我随便弄的,反正sqrt误差肯定不可能超过10
        while(l<=r)
        {
            int mid = l+r>>1;
            if(mid*mid>n/ii)
            {
                r = mid-1;
            }
            else
            {
                ss = mid;
                l = mid+1;
            }
        }
        num+=(ss+1>>1);//计算有多少个奇数
    }
    printf("%lld",num);
    return 0;
}
posted @ 2025-05-03 11:34  林晋堃  阅读(13)  评论(0)    收藏  举报