BZOJ2440 中山市选2011完全平方数(容斥原理+莫比乌斯函数)
如果能够知道不大于n的合法数有多少个,显然就可以二分答案了。
考虑怎么求这个。容易想到容斥,即枚举完全平方数。我们知道莫比乌斯函数就是此种容斥系数。筛出来就可以了。
注意二分时会爆int。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 100010 #define inf 2000000000 int T,n,prime[N],mobius[N],cnt=0; bool flag[N]; int calc(int n) { int s=n; for (int i=2;i*i<=n;i++) s+=mobius[i]*(n/(i*i)); return s; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj2440.in","r",stdin); freopen("bzoj2440.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif flag[1]=1;mobius[1]=1; for (int i=2;i<=N-10;i++) { if (!flag[i]) prime[++cnt]=i,mobius[i]=-1; for (int j=1;j<=cnt&&prime[j]*i<=N-10;j++) { flag[prime[j]*i]=1; if (i%prime[j]==0) break; mobius[prime[j]*i]=-mobius[i]; } } T=read(); while (T--) { n=read(); unsigned int l=1,r=inf;int ans; while (l<=r) { int mid=l+r>>1; if (calc(mid)>=n) ans=mid,r=mid-1; else l=mid+1; } cout<<ans<<endl; } return 0; }