题目传送门
分析:
我们先找一下一定不能匹配的数有哪些,显然是(1)与在区间((lfloorfrac{N}{2}
floor,N])的质数
剩下的数能不能全部匹配呢?我们尝试构造一下
把每个数分到其最大质因数的组中,对于每个质因数组,如果大小为偶数,那么就在内部全部匹配了
如果大小为奇数,由于其最大质因数(p)一定不大于(lfloorfrac{N}{2}
floor),那么一定存在(2p)不大于(N)
把(2p)这个数分到质因数(2)这个组中,进行匹配就好了
假设一定不能匹配的数有(D)个,答案即为(lfloorfrac{N-D+1}{2}
floor+D)
求一个大区间的质数个数直接使用Min_25筛
你高兴地敲完代码,往CF一交,发现TLE???
不是很懂。。
学习大佬代码之后发现预处理质数的倒数,把除法变成乘法直接快3倍???
然后语言选C++17就可以过???
不是很懂,这波真的不是很懂2333
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<iostream>
#include<map>
#include<string>
#define maxn 1000005
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
inline long long getint()
{
long long num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
long long N,S;
int pri[maxn],np[maxn],cnt;
long long G0[maxn];
long long num[maxn],tot;
int pos1[maxn],pos2[maxn];
double inv[maxn];
inline void init()
{
for(int i=2;i<maxn;i++)
{
if(!np[i])pri[++cnt]=i,inv[cnt]=1.0/pri[cnt];
for(int j=1;j<=cnt&&i*pri[j]<maxn;j++)
{
np[i*pri[j]]=1;
if(i%pri[j]==0)break;
}
}
}
inline int ID(long long x){return x<=S?pos1[x]:pos2[N/x];}
inline long long solve()
{
S=sqrt(N);tot=0;
for(long long i=1;i<=N;i++)
{
i=N/(N/i),num[++tot]=N/i;
G0[tot]=(num[tot]-1);
if(num[tot]<=S)pos1[num[tot]]=tot;
else pos2[i]=tot;
}
for(int j=1;j<=cnt;j++)for(int i=1;i<=tot&&1ll*pri[j]*pri[j]<=num[i];i++)
G0[i]-=G0[ID(num[i]*inv[j]+eps)]-(j-1);
return G0[1]-G0[2];
}
int main()
{
init();
int T=getint();
while(T--)
{
N=getint();
long long D=solve()+1;
printf("%lld
",(N-D+1)/2+D);
}
}