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

莫比乌斯函数。

完全平方数的倍数有如下特点。

1.首先不是质数的完全平方数可以忽略不计,因为它总是一个质数的完全平凡数的倍数。

2.每个质数i的完全平方数的倍数的个数为(n/(i*i))。

3.每对质数i,j的完全平方数的倍数已经在i和j时被重复统计了俩次,个数为(n/((i*j)^2))。

。。。。

。。。。

。。。。

这像什么?

这就是一个裸的莫比乌斯函数。

对于每个数i,它对答案的贡献就是μ[i]*(n/(i*i))。

所以预处理莫比乌斯函数的值,然后二分答案就可以了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 100000;

int mu[maxn+10],prime[maxn+10],cnt;
bool mark[maxn+10];

void predo() {
    mu[1]=1;
    for(int i=2;i<=maxn;i++) {
        if(!mark[i]) {
            mu[i]=-1;
            prime[++cnt]=i;            
        }
        for(int j=1,t;j<=cnt;j++) {
            t=prime[j]*i;
            if(t>maxn) break;
            mark[t]=1;
            if(i%prime[j]==0) {mu[t]=0; break;}
            mu[t]=-mu[i];
        }
    }
}

long long calc(long long x) {
    long long res=0,t=sqrt(x+0.5);
    for(long long i=1;i<=t;i++) 
        res+=mu[i]*(x/(i*i));    
    return res;
}

long long n,l,r,mid;

int main() {
    predo();    
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%lld",&n);
        l=1,r=n<<1;
        while(l<r) {
            mid=(l+r)>>1;
            if(calc(mid)>=n) r=mid;
            else l=mid+1;
        }
        printf("%lld\n",l);
    }
    return 0;
}
posted @ 2016-06-20 10:28  invoid  阅读(140)  评论(0编辑  收藏  举报