CodeForces1325E Ehab‘s REAL Number Theory Problem

原题链接

洛谷的
CF的
VJ的

题目描述

我没办法写出更短的意思了QwQ,洛谷太强了Orz。在此只能引用:

给一些数,每个的因数个数不超过 7 7 7,求最少选出多少个,使得乘积为完全平方。无解输出 − 1 -1 1

解题思路

有两个突破点,否则你推死也退不出来。
先把每个数分解质因数。如果某个质因数的次数是偶数那么就忽略,因为平方数每个质因数的次数就是偶数,反之就要去寻找哪个其他的数的质因数的次数也是奇数,两个一乘就变成偶数了。但是数的个数太多了,如果枚举肯定 T L E TLE TLE。那么我们就上第一个突破点:
最多有 7 7 7个因数
说明每个数最多有两个不同的质因数,因为如果有三个不同的质因数那么根据因数定理,就有 2 3 = 8 2^3=8 23=8个因数,大于 7 7 7个。只有两个质因数,很像一条边连接了两个点,所以可以把每个质因数当成点,然后两个不同的质因数连一条无向边。因为我们要处理的是次数是奇数的质因数,所以如果有次数是偶数的质因数就用 1 1 1代替这个位置。考虑有了这个图之后怎么计算是否可行,假设选择一条边就说明选了这个数,如果想要是完全平方数,则每个次数为奇数的质因子就一定选了偶数次,那么选出来的图中每个点的度数都是偶数:就是环啊!所以本题就变成了找一个最小环。因为我们要判断图是否连通,所以要枚举从每一个质数出发,用 b f s bfs bfs找环。但是质数很多,又要 T L E TLE TLE。我们来上第二个突破点:
每个数最大为 1 0 6 10^6 106
这个感觉就是一个普通的数据范围,但是并不简单。我们知道每个数 n n n都不会有两个及以上的质因数是大于 n \sqrt n n 的,因为如果有两个及以上,那么就有两个数乘起来大于 n n n,但是它应当是 n n n的因数,比 n n n小,矛盾。所以,这样建图,每条边连接的两个点都至少有一个在 1000 1000 1000以内的。所以枚举的起点在 1000 1000 1000以内就够了,更大的就一定已经遍历过了,没有必要再遍历了。因为质数有点大,所以要离散化所有质数。

丑陋代码

#include<bits/stdc++.h>
using namespace std;
const int NN=1e6+4;
int prime[NN],num[NN],head[NN],e[NN*2],ne[NN*2],idx,d[NN];
bool vis[NN];
void add(int u,int v)
{
    
    
	e[++idx]=v;
	ne[idx]=head[u];
	head[u]=idx;
}
int main()
{
    
    
	int cnt=0,maxs=1;
	num[1]=1;
	for(int i=2;i<NN;i++)
	{
    
    
		if(!vis[i])
		{
    
    
			prime[++cnt]=i;
			num[i]=cnt+1;
			if(i<1000)
				maxs++;
		}
		for(int j=1;i*prime[j]<NN;j++)
		{
    
    
			vis[i*prime[j]]=true;
			if(!(i%prime[j]))
				break;
		}
	}
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
    
    
		int x,q=1,p=1;
		scanf("%d",&x);
		for(int i=1;prime[i]*prime[i]<=x;i++)
		{
    
    
			int res=0;
			while(!(x%prime[i]))
			{
    
    
				res++;
				x/=prime[i];
			}
			if(res&1)
			{
    
    
				if(q>1)
					p=prime[i];
				else
					q=prime[i];
			}
		}
		if(x>1)
		{
    
    
			if(q>1)
				p=x;
			else
				q=x;
		}
		add(num[q],num[p]);
		add(num[p],num[q]);
	}
	int ans=1e9;
	for(int s=1;s<=maxs;s++)
	{
    
    
		queue<pair<int,int> >q;
		q.push(make_pair(s,0));
		memset(d,-1,sizeof(d));
		d[s]=0;
		while(q.size())
		{
    
    
			int u=q.front().first,fa=q.front().second;
			q.pop();
			for(int i=head[u];i;i=ne[i])
			{
    
    
				int v=e[i];
				if(v==fa)
					continue;
				if(d[v]==-1)
				{
    
    
					d[v]=d[u]+1;
					q.push(make_pair(v,u));
				}
				else
					ans=min(ans,d[u]+d[v]+1);
			}
		}
	}
	if(ans>n)
		printf("-1");
	else
		printf("%d",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44043668/article/details/109147562