完全平方数

Posted leiyuanze

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了完全平方数相关的知识,希望对你有一定的参考价值。

完全平方数

这是将我引上莫比乌斯反演的第一题 , 传送门:完全平方数

题目大意:求第 (k) 个不是完全平方数的倍数的数。

暴力似乎很爽,确实。
但可以以一个优美的算法切掉这一题—— (O(log nsqrt n))
优雅啊!

在一个大佬的帮助下——初一被清华锁定的 lzc 大佬——我明白了这道经典题的解法。

进入正题:

注:[p]表示,若 p 为真,其值为 1,否则为 0

莫比乌斯函数 (mu):默认你已懂其数学定义。

性质一:[sum_{d|n}mu(d) = [n=1]]

略作证明:

前置知识——二项式定理:[(a+b)^n = sum_{k=0}^n inom{n}{k} a^k b^{n - k}]
证明略。
现证性质一
(omega(n)) 表示 (n) 的不同质因子的个数
(n>1),则有:
[ egin{aligned} sum_{d|n}mu(d) &=sum_{i=0}^{omega(n)} inom{omega(n)}i (-1)^i &=sum_{i=0}^{omega(n)} inom{omega(n)}i (-1)^i 1^{omega(n)-i} &=(1-1)^{omega(n)} &=0 end{aligned} ]
(n=1),则易得[sum_{d|n} mu(d) = 1]
证毕。
那么如何做此题呢?
因为 (mu) 的定义,我们很容易想到如果一个数是完全平方数,那么它的 (mu) 就必然是 (0),否则就是 (1)(-1)
那第 (k) 个非完全平方数的倍数,记作(n) , 就要满足 (k = sum_{i=1}^nmu^2(i)) 且是所有满足此条中最小的(不要问我为何,你要知道,若 (n) 是完全平方数的倍数,那么它的贡献是 (0)
好,我们设[f(i)=max_{d^2|i}d]
那么, (n) 是不是完全平方数的倍数就可以表示为 ([f(n)=1])
代入关于 (k) 的式子,有:
[k = sum_{i=1}^n [f(i)=1]]
现在进入推导式子,一波骚操作:
先套性质一,然后地球人都明白 ({d|f(i)} Longleftrightarrow {d^2|i}) , 再改为先枚举 (d) 的形式······然后就差不多了,康康下边
[ egin{aligned} sum_{i=1}^n [f(i)=1] &=sum_{i=1}^n sum_{d|f(i)} mu(d) &=sum_{i=1}^n sum_{d^2|i} mu(d) &=sum_{d=1} sum_{d^2|i} mu(d) &=sum_{d=1} mu(d) sum_{d^2|i}1 &=sum_{d=1} mu(d) lfloor frac n{d^2} floor end{aligned} ]
没了
显然,这是 (O(sqrt n)) 的((mu) 提前筛出来)。
然后加上二分猜一个答案(n),用这种方法 (check) , 时间复杂度 (O(log nsqrt n))
然后加个数论分块优化(不过优化效果不大) , 时间复杂度 (O(log nsqrt{sqrt n}))
代码如下:

#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long LL;

int const N = 1e5;
int mo[N + 5] , prime[N + 5] , vis[N + 5] , tot = 0;
LL T , k;

inline LL read()
{
    char ch = getchar();
    LL res = 0;
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') res = res * 10 + ch - '0' , ch = getchar();
    return res; 
}

inline void getmo()
{
    mo[1] = 1 , vis[0] = vis[1] = 1;
    for(register int i = 2; i <= N; i++)
    {
        if (vis[i] == 0) prime[++tot] = i , mo[i] = -1;
        for(register int j = 1; j <= tot && prime[j] * i <= N; j++)
        {
            vis[prime[j] * i] = 1;
            if (i % prime[j] == 0) break;
            mo[prime[j] * i] = -mo[i];
        }
    }
    for(register int i = 1; i <= N; i++) mo[i] += mo[i - 1];
}

inline bool check(LL m)
{
    int j;
    LL res = 0;
    for(register int i = 1; i <= floor(sqrt(m)); i = j + 1)
    {
        j = floor(sqrt(m / (m / (i * i))));
        res += (m / (i * i)) * (mo[j] - mo[i - 1]);
    }
    return res >= k;
}

inline LL slove()
{
    LL l = k , r = k << 1 , res = 2e9 , mid;
    while (l <= r)
    {
        mid = (l + r) >> 1;
        if (check(mid)) r = mid - 1 , res = min(res , mid);
        else l = mid + 1;
    }
    return res;
}

int main()
{
    getmo();
    T = read();
    while (T--)
    {
        k = read(); 
        printf("%lld
" , slove());
    } 
}

以上是关于完全平方数的主要内容,如果未能解决你的问题,请参考以下文章

大等于n的最小完全平方数

c语言程序:编写函数,判断一个正整数是不是为完全平方数,并输出100以内的完全平方数。

蓝桥杯每日一真题—— [蓝桥杯 2021 省 AB2] 完全平方数(数论,质因数分解)

BZOJ_2440_[中山市选2011]完全平方数_容斥原理+线性筛

Python经典练习题1:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?

完全平方数