完全平方数(莫比乌斯反演+二分答案)
询问第k个不是完全平方数或完全平方数整数倍的整数。
1不视作完全平方数。
输入格式
第一行一个数t表示t组数据。
接下来t行每行一个整数表示k
输出格式
t行,每行一个整数表示答案。
输入样例
4
1
13
100
1234567
1
13
100
1234567
输出样例
1
19
163
2030745
数据规模:
对于20%的数据1<=k<=1000
对于50%的数据1<=k<=1000000
对于100%的数据1<=k<=1000000000
题意简洁又明了,但还是有些难度的。
首先,我们不可能根据k直接算出答案是多少,那对于一个确定的数x,是否能算出它是第几个非完全平方数呢?或者能否算出在它之前有多少个完全平方数呢?答案是肯定的。
在[1,x]中,4会出现x/4次,9会出现x/9次,以此类推,但是这样找会有重复,4和9每36就会重复一次,对于n²来说,会与n的约数m——m²重复,那么我们就可以用莫比乌斯函数(容斥原理)来筛掉重复的,就可以了。这样我们可以在sqrt(x)的时间内判断了。
又因为答案是有单调性的,所以我们可以对答案进行二分,加上前面的判断,时间复杂度为O(logn *sqrt(n))。
#include<fstream> #include<algorithm> #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> using namespace std; int T,k; int vis[100010],mu[100010],tot,pri[100010]; void Make_mu() { for (int i=2; i<=44800; i++) { if (vis[i]==0) { tot++; pri[tot] = i; mu[i] = -1; } for (int j=1; j<=tot; j++) { int x = i*pri[j]; if (x>100000) break; vis[x] = 1; if (i%pri[j]==0) { mu[x] = 0; break; } else mu[x] = -mu[i]; } } } int sum(int x) { int ret = x,cnt = 0; for (int i=2; i<=sqrt(x); i++) cnt = cnt-mu[i]*x/(i*i); return ret-cnt; } void Binary(int a,int b,int k) { long long l,r,mid; l = a; r = b; while (l+1<r) { mid = (long long)(l+r)/2; if (sum(mid)<k) l = mid; else r = mid; } printf("%d\n",r); } int main() { freopen("2236.in","r",stdin); freopen("2236.out","w",stdout); scanf("%d",&T); Make_mu(); while (T>0) { T--; scanf("%d",&k); Binary(0,1e9+2+1e9,k); } return 0; }