这题正解不用二分的呀…我弱只会二分的
(除了正解,好像有个更厉害的论文解法,然而根本看不懂论文…)
二分+洲阁筛
二分后,问题转化为判定性问题,即1~n有多少个质数
设g[i][j]表示1~j,与前i个质数互质的数的个数,得
g[i][j]=g[i−1][j]−g[i−1][j/prime[i]]
因为二分有多个n,不能递推需要记忆化搜索
只是这样搜肯定T,考虑一些剪枝
当
j<=p[i]
时,易得
g[i][j]=1
当
j<p[i]∗p[i]
时,即与
1∽j√
的质数互质,那么
g[i][j]
就是
1
及
这题二分的东西是单调不降的,要找最小的(显然?)
然后就可以做了(并不是),我一直T某几个点…于是….我优化了一下二分,判了一下数据范围减少二分次数(其实就是打表?)
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 11000100;
ll n;
bool v[maxn];
int g[maxn];
int p[maxn],pri;
void pre()
{
g[1]=0;
for(int i=2;i<maxn;i++)
{
if(!v[i]) p[++pri]=i;
for(int j=1;j<=pri;j++)
{
int k=i*p[j];
if(k>=maxn) break;
v[k]=true;
if(i%p[j]==0) break;
}
g[i]=g[i-1];
if(!v[i]) g[i]++;
}
}
ll G(const int i,ll j)
{
if(!i) return j;
if(i==1) return j-(j>>1);
if(j<maxn)
{
if(j<=p[i]) return 1ll;
if(j<p[i]*p[i]) return g[j]-i+1;
}
return G(i-1,j)-G(i-1,j/p[i]);
}
ll cal(ll x)
{
if(x<maxn) return g[x];
ll d=floor(sqrt(x));
return g[d]+G(g[d],x)-1;
}
int main()
{
pre();
scanf("%lld",&n);
ll l=1,r=22801763489,ans;
if(n>=900000000) l=20422213579;
if(n>=950000000) l=21610588367; else r=21610588367;
if(n>=970000000) l=22086742277; else r=22086742277;
if(n>=985000000) l=22444149523; else r=22444149523;
while(l<=r)
{
ll mid=(l+r)>>1;
ll tmp=cal(mid);
if(tmp>=n) r=mid-1;
else l=mid+1;
}
printf("%lld\n",r+1);
return 0;
}