【BZOJ2440】完全平方数(中山市选2011)-二分答案+莫比乌斯函数应用

测试地址:完全平方数
题目大意:求第K小的不是任何完全平方数倍数的正整数。
做法:这一题需要用到二分答案+莫比乌斯函数。
一般我们看到求第K小的啥啥啥一般就会先想到二分答案了,那么转化成判定性问题:在区间[1,x]中有多少个不是任何完全平方数倍数的整数?在区间[1,x]内的完全平方数有22,32,...,x2,要把是这些东西的倍数的数去掉,我们可以将每个完全平方数的平方根分解质因子,可以分成若干种质因子,那么根据容斥原理,答案就是:总数-平方根分解为1个互异质因子的平方数(如22,32)的倍数个数+平方根分解为2个互异质因子的平方数(如62,102)的倍数个数-…+(1)k×平方根分解为k个互异质因子的平方数的倍数个数。观察这一个定义,发现平方数i2倍数个数前面的符号就是莫比乌斯函数μ(i),又因为[1,x]i2的倍数有xi2个,所以答案就可以表示为xi=1μ(i)xi2,这样我们只需线性筛预处理出一定范围内的莫比乌斯函数值就可以了。总的时间复杂度约为O(KlogK),可以通过此题。
以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
int T;
ll k,mu[50010];
bool prime[50010];

void calc_mu()
{
  ll n=2*(ll)1e9,sq=(ll)sqrt(n)+1;
  for(ll i=1;i*i<=n;i++) mu[i]=1;
  for(ll i=2;i*i<=n;i++)
  {
    if (!prime[i])
    {
      for(ll j=1;i*j<=sq;j++)
      {
        prime[i*j]=1;
        if (!(j%i))
        {
          mu[i*j]=0;
          continue;
        }
        mu[i*j]*=-1;
      }
    }
  }
}

ll solve(ll x)
{
  ll s=x;
  for(ll i=2;i*i<=x;i++)
    s+=mu[i]*(x/(i*i));
  return s;
}

int main()
{
  scanf("%d",&T);
  calc_mu();
  while(T--)
  {
    scanf("%lld",&k);
    ll l=1,r=2*(ll)1e9;
    while(l!=r)
    {
      ll mid=(l+r)>>1,s;
      s=solve(mid);
      if (s>=k) r=mid;
      else l=mid+1;
    }
    printf("%lld\n",l);
  }

  return 0;
}
posted @ 2017-05-27 17:59  Maxwei_wzj  阅读(112)  评论(0编辑  收藏  举报