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; }
pain and happy in the cruel world.