完全平方数
假如说我们有了一个函数,这个函数 $f(n)$ 表示 $n$ 及其以下的数中的不是完全平方数的整数倍的数量。
然后我们想这个东西如何表示。
很容易联想到 $\mu$,再想一想的话,这个东西好像就是 $|\mu|$ 的前缀和,换句话说,就是 $\mu^2$ 的前缀和。
于是 $f(n)=\sum_{i=1}^{n}\mu^2(i)$。
然后问题是,这个东西怎么求。
我们显然没有什么现成的公式,考虑直接从意义层面思考这个问题。
考虑一个素数 $p_1$,它的平方 $p_1^2$ 的倍数全部不是合法的,我们从中筛去,一共有 $\lfloor\dfrac{n}{p_1^2}\rfloor$。但是我们再考虑另一个素数 $p_2$,显然我们也筛掉 $\lfloor\dfrac{n}{p_2^2}\rfloor$ 个数,但是我们多筛去了一部分数,这部分数有 $\lfloor\dfrac{n}{p_1^2p_2^2}\rfloor$ 个,我们还要把它加回来。
然后显然这个容斥的系数就是莫比乌斯函数。
不如说莫比乌斯函数其实是一种简单的容斥。
所以说我们最后的答案就是:
$$f(n)=\sum_{i=1}^{n}\mu^2(i)=\sum_{d=1}^{\sqrt{n}}\mu(d)\lfloor\dfrac{n}{d^2}\rfloor$$
然后考虑出来这个函数有什么用?
我们可以考虑二分答案。
然后就完了。
时间复杂度 $O(T\sqrt{n}\log n)$。
这个 $n$ 的范围适当调大,或者说能多大调多大。
当然如果有什么数学技巧可以对这个范围作近似当然最好。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| #include<iostream> #include<cstdio> #define ll long long using namespace std;
const ll M=1e5;
ll T,n,l,r,cnt;
ll mu[M+5],prime[M+5]; bool f[M+5];
inline void Init() { mu[1]=1;f[1]=1; for(ll i=2;i<=M;i++) { if(!f[i]) {prime[++cnt]=i;mu[i]=-1;} for(ll j=1;j<=cnt&&i*prime[j]<=M;j++) { f[i*prime[j]]=1; if(i%prime[j]==0) {mu[i*prime[j]]=0;break;} mu[i*prime[j]]=-mu[i]; } } }
inline bool check(ll x) { ll res=0; for(ll i=1;i*i<=x;i++) {res+=mu[i]*(x/i/i);} return res>=n; }
inline ll read() { ll ret=0,f=1;char ch=getchar(); while(ch<48||ch>57) {if(ch==45) f=-f;ch=getchar();} while(ch>=48&&ch<=57) {ret=(ret<<3)+(ret<<1)+ch-48;ch=getchar();} return ret*f; }
inline void write(ll x) { static char buf[22];static ll len=-1; if(x>=0) {do{buf[++len]=x%10+48;x/=10;}while(x);} else {putchar(45);do{buf[++len]=-(x%10)+48;x/=10;}while(x);} while(len>=0) putchar(buf[len--]); }
inline void writeln(ll x) {write(x);putchar(10);}
int main() {
Init();
T=read();
while(T--) { n=read(); l=1;r=1e10; while(l<r) { ll mid=(l+r)>>1; if(check(mid)) r=mid; else l=mid+1; } writeln(l); }
return 0; }
|