Vijos P1889 天真的因数分解

P1889天真的因数分解
标签: [显示标签]

描述

小岛: 什么叫做因数分解呢?
doc : 就是将给定的正整数n, 分解为若干个素数连乘的形式.
小岛: 那比如说 n=12 呢?
doc : 那么就是 12 = 2 X 2 X 3 呀.
小岛: 呜呜, 好难, 居然素数会重复出现, 如果分解后每一个素数都只出现一次, 我就会.

wish: 这样来说, 小岛可以正确分解的数字不多呀.
doc : 是呀是呀.
wish: 现在问题来了, 对于给定的k, 第 k 个小岛无法正确分解的数字是多少?

格式

输入格式

输入只有一行, 只有一个整数 k.

输出格式

输出只有一行, 只有一个整数, 表示小岛无法正确分解出来的第k个数字.

样例1

样例输入1[复制]

10

样例输出1[复制]

27

限制

对于30%的数据, k <= 2,000,000
对于100%的数据, 1 <= k <= 10,000,000,000

提示

前 10 个小岛无法正确分解出来的数字依次是: 4 8 9 12 16 18 20 24 25 27

题解
莫比乌斯反演+二分+容斥
先预处理出来 莫比乌斯函数,但是要反过来,也就是如果有平方因子,赋值为0,否则有奇数个因子赋值为1,偶数个赋值为-1
那么x以内包含i*i因子的个数为x/(i*i),根据容斥原理,x以内所有的含平方因子的数字有sum(x / (i * i) * Mob[i])个
so,这样加加减减就算出了x以内有多少个这样的数
然后二分答案就好

代码:

#include 
       
       
        
        
#define maxn (1000000 + 10)
typedef long long int LLI;
using namespace std;

bool isPrime[maxn];
LLI primeList[maxn],primeCount = 0;
short Mob[maxn];

void Mobius(LLI n) {
    memset(isPrime,true,sizeof(isPrime));
    isPrime[0] = false;
    isPrime[1] = false;
    Mob[1] = 0;
    for(int i = 2; i <= n; i ++) {
        if(isPrime[i]) {
            primeCount ++;
            primeList[primeCount] = i;
            Mob[i] = 1;
        }
        for(int j = 1; j <= primeCount; j ++) {
            if(i * primeList[j] > n)    break;
            isPrime[i * primeList[j]] = false;
            if(!(i % primeList[j])) {
                Mob[i * primeList[j]] = 0;
                break;
            } else   Mob[i * primeList[j]] = -Mob[i];
        }
    }
}

LLI sum(LLI x) {
    LLI re = 0;
    for(LLI i = 1; i * i <= x; i ++) {
        re = re + x / (i * i) * Mob[i];
    }
    return re;
}

int main() {
//    freopen("in.txt","r",stdin);
    Mobius(maxn);
    LLI k;
    scanf("%lld",&k);
    LLI l = 0,r = 25505460948LL,mid,ans;
    while(l <= r) {
        mid = (l + r) >> 1;
        if(sum(mid) >= k)   ans = mid,r = mid - 1;
        else                l = mid + 1;
    }
    printf("%lld\n",ans);
    return 0;
}

       
       



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值