Gym-102576A Bags of Candies

题目传送门

分析:
我们先找一下一定不能匹配的数有哪些,显然是\(1\)与在区间\((\lfloor\frac{N}{2}\rfloor,N]\)的质数
剩下的数能不能全部匹配呢?我们尝试构造一下
把每个数分到其最大质因数的组中,对于每个质因数组,如果大小为偶数,那么就在内部全部匹配了
如果大小为奇数,由于其最大质因数\(p\)一定不大于\(\lfloor\frac{N}{2}\rfloor\),那么一定存在\(2p\)不大于\(N\)
\(2p\)这个数分到质因数\(2\)这个组中,进行匹配就好了
假设一定不能匹配的数有\(D\)个,答案即为\(\lfloor\frac{N-D+1}{2}\rfloor+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",(N-D+1)/2+D);
	}
}

posted @ 2020-06-27 17:26  Izayoi_Doyo  阅读(331)  评论(0编辑  收藏  举报