[题解]完全平方数
一.前言
这题是洛谷的P4318来着。还有,好久没写题解了真是手生。听鹿乃的one,two专辑打代码真愉快
二.题意简述
这个题意已经明显的不能再明显了,就是让你求第 k 个无完全平方因子的数。
三.思路
(前面说了两个大点的废话来着)这道题康康数据范围,1e9 棘手。首先看到没有完全平方数,很显然的想到了莫比乌斯函数,(又是求个数还真是友好),于是尝试着将题目要求的东西用式子写出来。
欸写不出来,神奇。这种求第k个以前都是一个个去枚举来着?但是范围决定了不好枚举,那就考虑考虑二分?那么再看一看,如果定义 (f(x)) 为“小于等于x的无完全平方数的个数”,很明显,这是一个单调递增的东西,可以二分。于是程序的大致模样就出来了。
现在就差一个 (f) 函数的写法。先考虑一手能不能写成式子。
[f(x)=sum_{i=1}^{x}mu^2(i)\
或者;x-sumlimits_{i=1}^{x}[mu(i)+1=1]
]
上面那一个杜教筛筛不来,下面那一个反演演不出(也许可以顺着这个思路往下做?反正我是做不来。)
那么康康其他方法,em,容斥吧?于是感性的想到了
(f(x)=x-)为一个素数的平方的倍数的个数+为两个素数的积的平方的倍数的个数-为三个素数乘积的平方的倍数的数+...
从语句成分来看,答案由这些部分组成: “x的倍数的个数” , “k个素数的积平方”,“+或-”。
- 倍数的个数:直接向下取整除就好了嗷,小学数学。
- k个素数的积的平方:枚举肯定不是枚举 k,而是枚举 k 个素数的积。
- 系数:一个素数是 - ,两个素数是 + ,三个是 - ,又要根据这个数来判断由几个质数组成,所以赤裸裸的莫比乌斯函数。
啊。上面基本上都分析清楚了,整合一下就是
[f(x)=sumlimits_{i=1}^{i<=sqrt{x}}mu(i)lfloorfrac{x}{i^2}
floor
]
(枚举范围看看式子就知道了啊,不要为 1e9 操心)
CODE
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define m_for(i,a,b) for(int i=a;i<=b;++i)
const int MAXN=1e5+5;
ll n,m;
int prime[MAXN],mu[MAXN],tot,sum;
bool vis[MAXN],ans[MAXN];
void m_p(int x){
mu[1]=1;
m_for(i,2,x){
if(!vis[i])prime[++tot]=i,mu[i]=-1;
for(int j=1;j<=tot&&i*prime[j]<=x;++j){
vis[i*prime[j]]=1;
if(i%prime[j]==0)break;
mu[i*prime[j]]=-mu[i];
}
}
}
ll solve(ll x){
ll res=0;
for(int i=1;i*i<=x;++i)res+=1LL*x/i/i*mu[i];
return res;
}
ll l,r,mid,k,t;
int main(){
m_p(MAXN);
cin>>t;
while(t--){
cin>>k;
r=k<<1,l=k;
while(l<r){
mid=(l+r)>>1;
if(solve(mid)<k)l=mid+1;
else r=mid;
}
cout<<l<<endl;
}
return 0;
}