CF1622F Quadratic Set

一、题目

点此看题

二、解法

首先手玩可以得到一个貌似没什么用的性质,也就是最后是否是平方数取决于 \(\prod_{k\geq 0}(n-2k)\) 是否是平方数,由于我们还想要更简单的形式,这里我们不妨先只考虑 \(n\) 为偶数的情况:

\[\prod_{0<2k\leq n} 2k=2^{n/2}\cdot (n/2)! \]

那么我们在最坏情况下也只需要删除 \(2,n/2,n\) 这三项就可以获得构造,这说明答案的下界为 \(3\),所以我们只需要讨论答案是否为 \(0/1/2\),剩下的情况就给出 \(3\) 的上述构造即可。

\(0\) 可以直接判断乘积是不是完全平方数,直接对 \(\prod_{k\geq 0} (n-2k)\) 质因数分解即可;\(1\) 就需要找出质因数分解和上式相同的一个数,可以用哈希判断,就是给每个质因子分配一个 \(\tt ull\) 之内的整数,然后判断异或和是否相等即可;\(2\) 可以加上 \(\tt unordered\_map\) 来找异或和相等的点对。

三、总结

注意构造题有这样一种情况,也就是当答案范围很小的时候我们可以用讨论法解决问题,排除掉所有简单情况之后剩下的就是那种较复杂的情况。

#include <cstdio>
#include <cstdlib>
#include <unordered_map>
#include <ctime>
using namespace std;
const int M = 1000005;
#define ull unsigned long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,cnt,mn[M],a[M],p[M],vis[M];ull v[M],h[M];
unordered_map<ull,int> mp;
int random(int x)
{
	return (rand()*rand()+rand())%x;
}
void init()
{
	for(int i=2;i<=n;i++)
	{
		if(!vis[i]) p[++cnt]=i,mn[i]=i;
		for(int j=1;j<=cnt && i*p[j]<=n;j++)
		{
			vis[i*p[j]]=1;mn[i*p[j]]=p[j];
			if(i%p[j]==0) break;
		}
	}
}
signed main()
{
	n=read();init();srand(time(0));
	for(int i=1;i<=n;i++)
		v[i]=1ll*random(2e9)*random(2e9)+random(2e9);
	for(int i=n;i>=1;i-=2)
	{
		int x=i;
		while(x>1)
		{
			int p=mn[x];
			while(x%p==0) x/=p,a[p]^=1;
		}
	}
	int fl=1;for(int i=1;i<=n;i++) fl&=!a[i];
	if(fl)
	{
		printf("%d\n",n);
		for(int i=1;i<=n;i++)
			printf("%d ",i);
		puts("");return 0;
	}
	ull hs=0;
	for(int i=1;i<=n;i++) if(a[i]) hs^=v[i];
	for(int i=1;i<=n;i++)
	{
		int x=i;
		while(x>1)
		{
			int p=mn[x];
			while(x%p==0) x/=p,h[i]^=v[p];
		}
		h[i]^=h[i-1];
		if(h[i]==hs)
		{
			printf("%d\n",n-1);
			for(int j=1;j<=n;j++) if(j!=i)
				printf("%d ",j);
			puts("");return 0;
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(mp.count(hs^h[i]))
		{
			int j=mp[hs^h[i]];
			printf("%d\n",n-2);
			for(int k=1;k<=n;k++) if(k!=i && k!=j)
				printf("%d ",k);
			puts("");return 0;
		}
		mp[h[i]]=i;
	}
	printf("%d\n",n-3);
	for(int i=1;i<n;i++) if(i!=2 && i!=n/2)
		printf("%d ",i);
	puts("");return 0;
}
posted @ 2022-01-17 15:17  C202044zxy  阅读(96)  评论(0编辑  收藏  举报