【bzoj2440】[中山市选2011]完全平方数 莫比乌斯反演+容斥原理

Description

小 X 自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些
数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而
这丝毫不影响他对其他数的热爱。
这天是小X的生日,小 W 想送一个数给他作为生日礼物。当然他不能送一
个小X讨厌的数。他列出了所有小X不讨厌的数,然后选取了第 K个数送给了
小X。小X很开心地收下了。
然而现在小 W 却记不起送给小X的是哪个数了。你能帮他一下吗?

Input

包含多组测试数据。文件第一行有一个整数 T,表示测试
数据的组数。
第2 至第T+1 行每行有一个整数Ki,描述一组数据,含义如题目中所描述。

Output

含T 行,分别对每组数据作出回答。第 i 行输出相应的
第Ki 个不是完全平方数的正整数倍的数。

Sample Input

4 

1 

13 

100 

1234567 

Sample Output

1 

19 

163 

2030745 

HINT

对于 100%的数据有 1 ≤ Ki ≤ 10^9

, T ≤ 50

Source


先Orz各位大爷…我是抄题解的蒟蒻…

找第K个无平方因子数(sfn),容易发现是有单调性的,所以可以二分。

问题成了:求[1,n]有多少个数是sfn。

sfn的数量=总数量- {44}{99}{1616}...

这样就可以容斥原理了。如果这个数本身就不是sfn,那么它以及它的倍数都被删过了。所以接下来说的质数都是互不相同的质数。

对于[1, n ]的质数,sfn的数量=总数量-是一个质数的平方的倍数的数量+是两个质数的平方的倍数的数量-是三个质数的平方的倍数的数量…

然后发现是奇数个质数是负号,偶数个是正号,和莫比乌斯函数一样,这样就得到公式:

i<=nniiμ(i)

二分上界取2k就好?我取得INF。

O(n) 预理, O(n) 回答。

吐槽一句,关于二分时调整l和r好谜啊…

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

typedef long long LL;

const int SZ = 1000010;
const LL INF = 2000000010ll;

bool vis[SZ];
int pri[SZ],mu[SZ];

void shai(int n)
{
    mu[1] = 1;
    for(int i = 2,tot = 0;i <= n;i ++)
    {
        if(!vis[i]) pri[++ tot] = i,mu[i] = -1;
        for(int j = 1,m;j <= tot && (m = i * pri[j]) <= n;j ++)
        {
            vis[m] = 1;
            if(i % pri[j] == 0) { mu[m] = 0; break; }
            else mu[m] = - mu[i];
        }
    }
}

LL check(LL n)
{
    LL ans = 0;
    LL m = sqrt(n);
    for(int i = 1;i <= m;i ++)
        ans += n / (i * i) * mu[i];
    return ans;
}

LL div(int n)
{
    LL l = -1,r = INF,ans;
    while(l <= r)
    {
        LL mid = (l + r) >> 1;
        LL tmp = check(mid);
        if(tmp >= n)  r = mid - 1,ans = mid;
        else l = mid + 1; 
    }
    return ans;
}

int main()
{
    int T;
    scanf("%d",&T);
    shai(sqrt(INF));
    while(T --)
    {
        int n;
        scanf("%d",&n);
        printf("%lld\n",check(n));
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值