1. 程式人生 > >BZOJ2440(完全平方數)二分+莫比烏斯容斥

BZOJ2440(完全平方數)二分+莫比烏斯容斥

題意:完全平方數是指含有平方數因子的數。求第ki個非完全平方數。


解法:比較明顯的二分,getsum(int middle)求1-middle有多少個非完全平方數,然後二分。求1-middle的非完全平方數個數可以用總數減掉完全平方數個數。計算完全平方數的個數用容斥:

    首先加上n/(2*2)+n/(3*3)+n/(5*5)+n/(7*7)...+...然後減掉出現兩次的,然後加上三次的...奇加偶減。這就是mou的原型,用mou陣列計算很簡單;

       

程式碼:


  
  1. /******************************************************
  2. * @author:xiefubao
  3. *******************************************************/
  4. #pragma comment(linker, "/STACK:102400000,102400000")
  5. #include
    <iostream>
  6. #include <cstring>
  7. #include <cstdlib>
  8. #include <cstdio>
  9. #include <queue>
  10. #include <vector>
  11. #include <algorithm>
  12. #include <cmath>
  13. #include <map>
  14. #include <set>
  15. #include <stack>
  16. #include <string.h>
  17. //freopen ("in.txt" , "r" , stdin);
  18. using namespace std;
  19. #define eps 1e-8
  20. #define zero(_) (abs(_)<=eps)
  21. const double pi= acos( -1.0);
  22. typedef unsigned long long LL;
  23. const int Max= 100010;
  24. const LL INF= 2e16+ 7;
  25. LL mou[Max];
  26. void init()
  27. {
  28. for(LL i= 2; i<Max; i++)
  29. {
  30. if(!mou[i])
  31. {
  32. mou[i]=i;
  33. for(LL j=i*i; j<Max; j+=i)
  34. mou[j]=i;
  35. }
  36. }
  37. mou[ 1]= 1;
  38. for( int i= 2; i<Max; i++)
  39. {
  40. if(i/mou[i]%mou[i]== 0) mou[i]= 0;
  41. else mou[i]=-mou[i/mou[i]];
  42. }
  43. }
  44. int k;
  45. LL getnum(LL middle)
  46. {
  47. LL ans= 0;
  48. for(LL i= 1; i*i<=middle; i++)
  49. {
  50. ans+=mou[i]*(middle/(i*i));
  51. }
  52. return ans;
  53. }
  54. int main()
  55. {
  56. init();
  57. int t;
  58. cin>>t;
  59. while(t--)
  60. {
  61. scanf( "%d",&k);
  62. LL left= 1,right=INF;
  63. while(left<=right)
  64. {
  65. int middle=(left+right)/ 2;
  66. if(getnum(middle)<k)
  67. left=middle+ 1;
  68. else
  69. right=middle -1;
  70. }
  71. cout<<left<< '\n';
  72. }
  73. return 0;
  74. }