二分+mu函数实质及应用(原理)!——bzoj2440好题
首先想到用二分来判断
不是平方数的倍数,即没有次数>=2的质因子
显然用容斥原理,即所有答案-1个质因子的平方的所有倍数+2个质因子的所有平方倍...
等价于对于每个数,如果它有奇数个质因子,那么其贡献系数是-1,反之则是1,
如果自己本身有平方因子(比如2*2*3),那么其贡献系数是0,因为已经被前面的筛掉了(1的时候+1,2,3的时候-1,2*3的时候+1,最后已经成为0了),根本不用去管它
那么可以发现i的系数恰好是mu[i]
其实由这题可以发现mu[i]函数的意义,即容斥系数
本题用容斥筛出i的倍数时 对应的系数恰好是 mu[i]是因为:mu[i]的本质就是来筛i的倍数的
设f(n)是原函数,g(n)是和函数
mu[p1]=-1 是因为 f(n)必须要减去一个g(n/p1)
mu[p1*p2]=1是因为 f(n)=g(n)-g(n/p1)-g(n/p2),多减掉了一个g(n/p1/p2)
mu[p1^k*p2]=0 是因为 f(n)=g(n)-g(n/p1)-g(n/p2)+g(n/p1/p2) 里 的g(n/p1^k/p2)已经被做成0了
g(n/p1的所有倍数)系数-1,g(n/p2的所有倍数)系数-1,g(n/p1/p2)的所有倍数系数+1,所以g(n/p1/p2的所有倍数)的系数最后变成了0,包括g(n/p1/p1/p2)之类的系数
所以不需要再加减了
#define N 100000 using namespace std; typedef long long LL; const LL inf = (1LL<<31)-1; const int MAXN = 100011; LL l,r; int ans; int mobius[MAXN],k; int prime[MAXN],cnt; bool ok[MAXN]; inline int getint() { int w=0,q=0; char c=getchar(); while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w; } inline void init(){ mobius[1]=1; for(int i=2;i<=N;i++) { if(!ok[i]) prime[++cnt]=i,mobius[i]=-1; for(int j=1;j<=cnt && prime[j]*i<=N;j++) { ok[i*prime[j]]=1; if(i%prime[j]) mobius[i*prime[j]]=-mobius[i]; else { mobius[i*prime[j]]=0; break; } } } } inline bool check(LL x){ LL div=sqrt(x); int tot=0; for(int i=1;i<=div;i++) { tot+=mobius[i] * (x/(i*i)); } //tot=x-tot; if(tot>=k) return true; return false; } inline void work(){ init(); int T=getint(); LL mid; while(T--) { k=getint(); l=1; r=inf; ans=inf; while(l<=r) { mid=(l+r)/2; if(check(mid)) ans=mid,r=mid-1; else l=mid+1; } printf("%d\n",ans); } } int main() { work(); return 0; }