BZOJ 2440 完全平方数 (容斥原理+莫比乌斯函数)

这题是莫比乌斯反演的入门题。

好吧,就是求莫比乌斯函数,没用上反演。


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


Solution

由于这题是数论中的water problem,于是长话短说。

1.线性筛筛出莫反函数
2.二分答案
3.用容斥原理来比较二分出的数的位置和k,思想很简单,即用mid减去1~mid中的完全平方数的个数即可得到非完全平方数的个数,直接 O(n) 枚举出完全平方数的自共轭因子,然后再用莫比乌斯函数来进行容斥并累计个数,原理自行体会。


Code

#include  
#include 
#include 
#include 
#include 
#include 
#define N 100000

using namespace std;

int T, cnt, prime[N+10], miu[N+10], k;
bool vis[N+10];

void Get_miu(){
    miu[1] = 1;
    vis[1] = true;

    for(int i = 2; i <= N; i++){
      if(!vis[i]){
        prime[++cnt] = i;
        miu[i] = -1;
      }
      for(int j = 1; j <= cnt && i * prime[j] <= N; j++){
        vis[i * prime[j]] = true;
        if(i % prime[j] == 0){
          miu[i * prime[j]] = 0;
          break;
        }
        else  miu[i * prime[j]] = - miu[i];
      }
    }
}

int main(){

    Get_miu();

    scanf("%d", &T);

    while(T --){
      scanf("%d", &k);
      long long L = 0, R = 5*1e9;
      while(L + 1 < R){
        int mid = (L + R) >> 1, ans = 0;
        for(int i = 1; i * i <= mid; i++)
          ans += mid / (long long)(i * i) * miu[i];
        if(ans < k)  L = mid;
        else  R = mid;
      }
      printf("%lld\n", R);
    }

    return 0;
} 

注意:线性筛做到的范围不要太大,N取100000就够了,二分也要注意范围,否则会TLE,所以预处理和二分上下界一定要把持住,一不小心就会
- By Ab.Ever

你可能感兴趣的:(数论,&,数学,莫比乌斯反演,&,杜教筛,容斥原理,BZOJ)