51nod 1616 最小集合

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1616


该题目的就是找到集合内的数的所有最大公约数。


题解:

1. 首先容易证明:x是集合内的数一定是当且仅当,x为初始给定的集合内的n个数中的某几个数的最大公约数。

2.

若令f(x)代表集合内能被x整除的数的个数。

那么若某个数y,集合内有f(y)个数被y整除,这些数的集合设为S,那么S内的最大公约数设为k。

那么f(k)>=|S|=f(y)。 

又有y|k,所以f(k)<=f(y)。

从而有f(y)=f(k)。


因此对于y的集合S,一定有一个公约数k,f(k)=f(y), y|k。

所以如果对于y*2, y*3...,其f值都不跟f(y)相等,那么找不到k,k就只能是y, y就是最大公约数

如果存在某个f(y'=y*t)值跟f(y)相等。那么y'对应的集合S'刚好就是y对应的集合S。

也就是说集合S的最大公约数一定是y的倍数,因此不可能再找到一个集合其公约数是y,(因为集合S已经是最大的可能集合了,被排除)。

因此y不可能是要找的最大公约数。


综上所述,题目转化为:


1.先求f值,

2. 然后只要对y,找其2*y,3*y...,是否存在某个f值与f(y)相等,来判断y是否是所求的数


算法的两部分,均能用Eraosthenes筛素数法的类似流程来实现,复杂度均为nlogn,n为数的最大范围。

不知道还有更好的方法么,如果有,那基本就是O(n)的方法,没想到。


AC代码:

#include<iostream>

using namespace std;

#define mylen 1000001
int n, myresult;
int f[mylen];

void getInput()
{
	scanf("%d", &n);
	int tmp;
	for (int i = 0; i < n; ++i)
	{
		scanf("%d", &tmp);
		f[tmp] = 1;
	}
}

void eraosthenes_Sieve(int n)
{
	for (int i = 1; i <= n; ++i)
	{
		for (int j = (i<<1); j <= n; j+=i)
		{
			if (f[j])
			{
				++f[i];
			}
		}
	}

	bool is_target = true;

	for (int i = 1; i <= n; ++i)
	{
		if (f[i])
		{
			is_target = true;
			for (int j = (i<<1); j <= n; j += i)
			{
				if (f[j] == f[i])
				{
					is_target = false;
					break;
				}
			}
			if (is_target)
			{
				++myresult;
			}
		}
	}
}

int main()
{
	getInput();
	eraosthenes_Sieve(1000001);
	printf("%d\n", myresult);
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值