BZOJ2440: [中山市选2011]完全平方数

  • 双倍经验:vijos1889天真的因数分解
  • 思考如何计算1~x内的非完全平方数
  • 容斥原理1~x内的非完全平方数 = 所有的数 - 所有有一个质数平方因子的数(4,9,25……的倍数)+所有有两个质数平方因子的数(36,100,……的倍数)-……
  • 然后枚举所有 i * i < x ,这些i是所有可能的充当平方因子的质数,然后发现容斥原理里的系数正好等于 mu[i] ,所以每个算其对答案的贡献就是   mu[ i ] * x / ( i* i )
  • 这里的mu[i]是莫比乌斯函数
  • 所以预处理莫比乌斯函数,就可以在根号x下解决了
  • 然后二分答案寻找第k个非完全平方数
  • 注意二分答案的时候不是直接取f(mid)==k的那个mid,因为mid本身不一定是非完全平方数
  • 代码:
     1 #include <bits/stdc++.h>
     2 #define nmax 2000050
     3  
     4 using namespace std;
     5 typedef long long ll;
     6 ll x;
     7 int table[nmax]={0},pri[nmax],mu[nmax];
     8 int cp=-1;
     9  
    10 void getmu(){  //算莫比乌斯函数
    11     for (int i=2; i<nmax; i++) {
    12         if( !table[i] ) { pri[++cp]=i; mu[i]=-1; }
    13         for (int j=0; j<=cp; j++) {
    14             ll t=pri[j]*i;
    15             if(t>=nmax) break;
    16             table[t]=1;
    17             if(i%pri[j]==0) { mu[t]=0; break;}
    18             mu[t]=mu[i]*(-1);
    19         }
    20     }
    21     mu[1]=1;
    22 }
    23  
    24 ll f(ll a){  //算1~a之间的非完全平方数的数量(包括a)
    25     ll ans=0;
    26     for (ll i=1; i*i<=a; i++) ans+=mu[i]*a/(i*i);
    27     return ans;
    28 }
    29  
    30 int main(){
    31     getmu();
    32     int t;
    33     cin>>t;
    34     while(t--){
    35         scanf("%lld",&x);
    36         //二分答案(这里mid的那个值也要是非完全平方数才行)
    37         ll l=x,r=3*x,mid,ans;
    38         while(l<r) {
    39             mid=(l+r)>>1;
    40             ll t=f(mid);
    41             if( t>=x ) { ans=mid; r=mid;}
    42             else l=mid+1;
    43             if(l==r) ans=l;
    44         }
    45         cout<<ans<<endl;
    46     }
    47     return 0;
    48 }

     


     

posted @ 2019-09-06 14:09  连昵称都不能重复  阅读(195)  评论(0编辑  收藏  举报