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

怎么感觉一直在做市选的说。。搞得在中山的我都没信心了。。。

好吧做这题主要是冲着莫比乌斯反演去的,然后实际上也是容斥原理的应用,跟反演没什么关系,但是莫比乌斯函数的一个应用。

首先将题目询问第k个无平方因子数,那么我立刻想到的是,这些数在莫比乌斯函数中的值是0(但是这个没什么用)

实际上的做法是二分枚举范围(我觉得这个是神来之笔),然后求这个范围中有多少个无平方因子数。

那么个数怎么求,就是一个容斥原理的应用了:无平方因子数个数=包含0个质数平方的数个数(可能这一项有点难理解,但实际上就是总数)-包含1个质数平方的数个数+包含2个质数质数平方的数个数-包含3个质数平方的数个数……

(PS:具体这个数怎么求呢,实际上是所以包含x个质数平方因子的数,用总数除以平方就可以得出这个平方出现了多少次了,举个例子,范围为40,那包含1个质数平方的数个数是多少呢,就是40/4+40/9+……)

那么再来回顾一下莫比乌斯函数的定义,含有偶数个不同质数的数 函数值为1,含有奇数个不同质数的数 函数值为-1

发现了什么?莫比乌斯函数值正好和上面容斥式子的正负是一样的!举个例子,4现在我可以轻松的告诉你,ta在容斥式子里面是减去的,因为ta包含一个质数的乘积,但是我也可以说,因为2的莫比乌斯函数是-1。

那么具体做法就是枚举全部的平方数,根据莫比乌斯函数取决他是加还是减。1*1也是平方数啊,n/1*1*u(1)不就是总数咯~

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
int pr,prime[210000],u[210000];
bool v[210000];
void mobius_inversion()
{
    pr=0;u[1]=1;
    memset(v,false,sizeof(v));
    for(int i=2;i<=210000;i++)
    {
        if(v[i]==false)
        {
            u[i]=-1;
            prime[++pr]=i;
        }
        for(int j=1;j<=pr&&i*prime[j]<=210000;j++)
        {
            v[i*prime[j]]=true;
            if(i%prime[j]==0){u[i*prime[j]]=0;break;}
            u[i*prime[j]]=-u[i];
        }
    }
}
LL check(LL x)
{
    LL sum=0,t=sqrt(x);
    for(int i=1;i<=t;i++)sum+=u[i]*x/(i*i);
    return sum;
}
int main()
{
    mobius_inversion();
    
    int T;
    scanf("%d",&T);
    while(T--)
    {
        LL k;
        scanf("%lld",&k);
        
        LL l=k,r=2100000000LL,ans;
        while(l<=r)
        {
            LL mid=(l+r)/2;
            if(check(mid)>=k)
            {
                ans=mid;
                r=mid-1;
            }
            else l=mid+1;
        }
        printf("%lld\n",ans);
    }
    return 0;
 } 

 

posted @ 2017-11-26 16:05  AKCqhzdy  阅读(206)  评论(0编辑  收藏  举报