【BZOJ2440&&2986】完全平方数

题意:求第k个无平方因子数是多少

无平方因子数(square-free number),即质因数分解之后所有质因数的次数都为1的数

膜拜Po姐姐

二分答案 设二分后值为x 我们考虑前x个数中是否含有超过k个不是平方因子的数

我们考虑平方因子一定含有至少一个质数的平方 

那么考虑容斥,即质数平方个数为0的数的个数-质数平方个数为1的数的个数+质数平方个数为2的数的个数-……

公式表示的话 设有p个素数而且选择了i个素数是平方,且任选i个素数的乘积为d,得到公式

$f(x)=\sum_{i=0}^{p}(-1)^i \lfloor \frac{n}{d^{2}}  \rfloor(d为任意i个素数相乘的积)$

发现d最多选择到$\sqrt{ n }$ 那么我们可以考虑直接枚举d 于是问题变成了如何快速判断d的贡献

莫比乌斯函数即是。

然后根据莫比乌斯函数的定义式,将式子化为$f(x)=\sum_{d=1}^{\sqrt{x}} \mu (d) \lfloor \frac{n}{d^{2}} \rfloor $

所以我们枚举根号n内的所有答案 带入计算即可 复杂度$O(\sqrt{n}log{n})$

/*To The End Of The Galaxy*/
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iomanip>
#include<bitset>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#define debug(x) cerr<<#x<<"="<<x<<endl
#define INF 0x7f7f7f7f
#define llINF 0x7fffffffffffll
#define P(x,y) (((x-1)*c)+y)
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
inline int init()
{
    int now=0,ju=1;char c;bool flag=false;
    while(1)
    {
        c=getchar();
        if(c=='-')ju=-1;
        else if(c>='0'&&c<='9')
        {
            now=now*10+c-'0';
            flag=true;
        }
        else if(flag)return now*ju;
    }
}
inline long long llinit()
{
    long long now=0,ju=1;char c;bool flag=false;
    while(1)
    {
        c=getchar();
        if(c=='-')ju=-1;
        else if(c>='0'&&c<='9')
        {
            now=now*10+c-'0';
            flag=true;
        }
        else if(flag)return now*ju;
    }
}
int n=100000,prime[100005],cnt,mu[100005];
bool vis[100005];
void getmu()
{
    mu[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!vis[i])
        {
            vis[i]=1;
            mu[i]=-1;
            ++cnt;prime[cnt]=i;
        }
        for(int j=1;j<=cnt&&prime[j]*i<=n;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            mu[i*prime[j]]=-mu[i];
        }
    }
}
#define mid ((l+r)>>1)
int cas;
ll l,r;
ll calc(ll x)
{
    ll res=0;
    for(int i=1;i*i<=x;i++)
    {
        res+=x/(i*i)*mu[i];
    }
    return res;
}
int main()
{
    cas=init();
    getmu();
    int k;
    ll ans;
    for(int i=1;i<=cas;i++)
    {
        k=init();
        l=1,r=k*2;
        while(l<=r)
        {
            if(calc(mid)>=k)
            {
                ans=mid;
                r=mid-1;
            }
            else l=mid+1;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2017-03-24 16:37  redwind  阅读(266)  评论(0编辑  收藏  举报