bzoj 2440

 

题意:有一个从小到大的由不包含平方约数的数组成的数列,从1开始,求第k项。

“满足某种限制的数的第k个”+二分答案="前n个数有多少个数满足限制“

求[1,n]中有多少个数没有平方约数,我们考虑求满足要求的数的补集。

求[1,n]中有多少个数有平方约数,我们考虑枚举约数后用容斥解决。

设Ai为包含[1,n]中所有为pi*pi的倍数的数的集合,因为一个数存在平方约数当且仅当它是某个(可能不止一个)质数的平方的倍数,所有转换后的问题的答案是(假如1~sqrt(n)只有3个质数):

|A1 U A2 U A3 ... | = |A1|+|A2|+|A3|-|A1 and A2|-|A1 and A3|-|A2 and A3|+|A1 and A2 and A3|

我们发现是奇数个质数的积的倍数前面的符号都是-1,偶数个则是1,这正好符合Mobius函数的定义,于是我们可以枚举所有不包含平方因子的数i,然后floor(n/(i*i))为是它的倍数的数的个数,而它们前面的符号为mobius[i]。

 

 1 /**************************************************************
 2     Problem: 2440
 3     User: idy002
 4     Language: C++
 5     Result: Accepted
 6     Time:1232 ms
 7     Memory:1232 kb
 8 ****************************************************************/
 9  
10 #include <cstdio>
11 #include <cmath>
12  
13 int prm[6000], isnot[50010], mu[50010], ptot;
14  
15 void init() {
16     mu[1] = 1;
17     for( int i=2; i<=50000; i++ ) {
18         if( !isnot[i] ) {
19             prm[++ptot]=i;
20             mu[i] = -1;
21         }
22         for( int j=1; j<=ptot && prm[j]*i<=50000; j++ ) {
23             isnot[i*prm[j]]=true;
24             if( i%prm[j]==0 ) {
25                 mu[i*prm[j]]=0;
26                 break;
27             }
28             mu[i*prm[j]]=-mu[i];
29         }
30     }
31 }
32 int calc( int n ) {
33     int rt = 0;
34     int maxi = (int)ceil(sqrt(n));
35     for( int i=1; i<=maxi; i++ )
36         rt += mu[i]*(n/(i*i));
37     return rt;
38 }
39 int nth( int k ) {
40     int lf=1, rg=2000000000;
41     while( lf<rg ) {
42         int mid=lf+((rg-lf)>>1);
43         int cnt=calc(mid);
44         if( cnt<k ) lf=mid+1;
45         else rg=mid;
46     }
47     return lf;
48 }
49  
50 int main() {
51     int T;
52     init();
53     scanf( "%d", &T );
54     while( T-- ) {
55         int k;
56         scanf( "%d", &k );
57         printf( "%d\n", nth(k) );
58     }
59 }
View Code

 

posted @ 2015-03-29 21:57  idy002  阅读(269)  评论(0编辑  收藏  举报