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; }