链接:
#include <stdio.h>
int main()
{
puts("转载请注明出处[vmurder]谢谢");
puts("网址:blog.youkuaiyun.com/vmurder/article/details/44646027");
}
题解:
给出PoPoQQQ大爷的题解链接:
http://blog.youkuaiyun.com/popoqqq/article/details/42076037
我太弱,可以直接看大爷的不用看我的。
首先整体思想上我们可以二分check前x个数中有多少个符合要求的数。
然后这个怎么check呢?发现我们枚举每个数,看范围内是它的平方的倍数的数有多少个就行了。然后发现容斥一下,有些数是要加的,而有些数是要减的,比如枚举到3,那么3*3*4=36被删了一次,而枚举到2时其实2*2*9=36就已经被删了一次啦。所以在枚举2*3=6时,其实我们是要加而不是减的。
然后这个加减的方向正好是莫比乌斯函数mu~~
而莫比乌斯函数先线性筛出来就好了。
莫比乌斯函数:
当
d=1
时:
μd=1
当
d
可以被拆解成
μd=(−1)k
其它情况下:
μd=0
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 44723
#define inf 0x3f3f3f3f
using namespace std;
int mu[N],prime[N],cnt;
bool vis[N];
void shake()
{
int i,j;
mu[1]=1;
for(i=2;i<N;i++)
{
if(!vis[i])
{
mu[i]=-1;
prime[++cnt]=i;
}
for(j=1;i*prime[j]<N&&j<=cnt;j++)
{
vis[i*prime[j]]=true;
if(i%prime[j])mu[i*prime[j]]=-mu[i];
else break;// 此处应该给mu赋0,但是天生是0就不管了
}
}
}
int check(int x)
{
int i,ret=0;
for(i=1;i*i<=x;i++)
ret+=x/(i*i)*mu[i];
// i^2 的倍数有x/(i*i)个
// 容斥后贡献方向是 mu
return ret;
}
int main()
{
freopen("test.in","r",stdin);
shake();
int i,j,k,g;
for(scanf("%d",&g);g--;)
{
scanf("%d",&k);
int l=1,r=k<<1,mid; // 二分上界是有证明的
while(l+1<r) // Orz PoPoQQQ大爷。妈呀这是什么二分这么快!!
{
mid=(l>>1)+(r>>1)+(l&r&1);
if(check(mid)>=k)r=mid;
else l=mid;
}
printf("%d\n",check(l)>=k?l:r);
}
return 0;
}