【BZOJ2440】完全平方数 [莫比乌斯函数]

完全平方数

Time Limit: 10 Sec  Memory Limit: 128 MB
[Submit][Status][Discuss]

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

Main idea

  询问第 k 个不含完全平方因子的数。

Source  

  显然我们可以简化一下问题,二分答案。那么我们就只需要知道:1~n中 不含完全平方因子 的数的个数。

  然后我们思考一下容斥,用(总数-完全平方数个数):完全平方数个数 = 至少有1个质数平方因子的数 - 至少2个质数平方因子的数 + 至少3个质数平方因子的数……
  (假设你有一堆质数 {P_1, ..., P_n},A_i 表示的是 包含 P_i^2 作为因子的数的集合)  

  也就是:奇数个质数平方因子的数 - 偶数个质数平方因子的数
  然后我们发现,那么可以枚举一个d,删除d^2相关,这时候系数也就是μ(d),求一下莫比乌斯函数即可。当d有奇数个质数因子的时候,删除的是有奇数个质数平方因子中d^2的倍数。
  整理成式子也就是:

Code

 1 #include<iostream>  
 2 #include<string>  
 3 #include<algorithm>  
 4 #include<cstdio>  
 5 #include<cstring>  
 6 #include<cstdlib>  
 7 #include<cmath>
 8 using namespace std; 
 9 typedef long long s64;
10  
11 const int ONE = 44725;
12    
13 int T;
14 int n,m;
15 int prime[ONE],miu[ONE],isp[ONE],p_num;
16  
17 int get() 
18 {
19         int res=1,Q=1;  char c;
20         while( (c=getchar())<48 || c>57)
21         if(c=='-')Q=-1;
22         if(Q) res=c-48; 
23         while((c=getchar())>=48 && c<=57) 
24         res=res*10+c-48; 
25         return res*Q; 
26 }
27  
28 void Getmiu(int MaxN)
29 {
30         miu[1] = 1;
31         for(int i=2; i<=MaxN; i++)
32         {
33             if(!isp[i])
34                 isp[i] = 1, prime[++p_num] = i, miu[i] = -1;
35             for(int j=1; j<=p_num, i*prime[j]<=MaxN; j++)
36             {
37                 isp[i * prime[j]] = 1;
38                 if(i % prime[j] == 0)
39                 {
40                     miu[i * prime[j]] = 0;
41                     break;
42                 }
43                 miu[i * prime[j]] = -miu[i];
44             }
45         }
46 }
47  
48 s64 Check(s64 n)
49 {
50         s64 res = 0 ,Q = sqrt(n);
51         for(int d=1; d<=Q; d++)
52             res += miu[d] * (n/(d*d));
53         return res;
54 }
55  
56 void Solve()
57 {
58         n = get();
59         s64 l = 0, r = 2e9;
60         while( l < r-1 )
61         {
62             s64 mid = (l+r)>>1;
63             if(Check(mid) < n) l = mid;
64             else r = mid;
65         }
66          
67         if(Check(r) <= n) printf("%d", r);
68         else printf("%d", l); 
69         printf("\n");
70 }
71  
72 int main()
73 {
74         Getmiu(ONE-1);
75         T = get();
76         while(T--)
77             Solve();
78 }
79 
View Code

 

posted @ 2017-04-02 11:00  BearChild  阅读(317)  评论(0编辑  收藏  举报