• 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
    ", nth(k) );
    58     }
    59 }
    View Code
  • 相关阅读:
    OpenCV实现基于傅里叶变换的旋转文本校正
    【来龙去脉系列】QRCode二维码的生成细节和原理
    软件License设计
    常见加密算法简析
    【来龙去脉系列】RSA算法原理
    单目相机标定原理
    CYQ.Data 支持 PostgreSQL 数据库
    ASP.NET Aries 高级开发教程:主题样式及多语言(标签化控制)
    ASP.NET Aries 高级开发教程:Excel导入之代码编写(番外篇)
    ASP.NET Aries 高级开发教程:Excel导入配置之规则说明(下)
  • 原文地址:https://www.cnblogs.com/idy002/p/4376492.html
Copyright © 2020-2023  润新知