EOJ Monthly 2019.7 (based on July Selection) - B. 最小公倍数

单点时限: 1.0 sec

内存限制: 256 MB

QQ小方以前不会求最小公倍数,现在他会了,所以他急切的想教会你。

两个或多个整数公有的倍数叫做它们的公倍数,其中除 0 以外最小的一个公倍数就叫做这几个整数的最小公倍数。

我们经常用质因数分解法来求最小公倍数:把每个数分别分解质因数,再把各数中的全部公有质因数提取出来连乘,所得的积就是这几个数的最大公约数。

单单讲给你听肯定是不够的,为了表现自己,QQ小方现在要考考你。

QQ小方自己刚刚做了一道题目:三个小朋友经常去图书馆,分别每隔 3 天、 2 天、 5 天去图书馆借书,他们恰好在第一天的时候都去了图书馆,要让QQ小方求出他们最少过几天又会在同一天去图书馆。这个问题对已经会了最小公倍数的QQ小方来说很简单。

QQ小方决定将问题升级,QQ小方现在会召集一些小朋友,他们会分别间隔一定的天数规律地来到图书馆,而一旦某一天图书馆来了至少一个小朋友,QQ小方都会告诉你这天的日期。QQ小方会在第一天的时候召集所有人来到图书馆。他现在想知道,对于他给定的日期,他最少需要召唤多少小朋友。

QQ小方只会记录在 2⋅105 以内出现小朋友的日期,也就是说,后续的日期你可以忽略不计。当然QQ小方也可以在任意时刻结束记录。

QQ小方的记录当然是不会出错的,也就是输入的数据保证存在合法的解。

输入格式

输入数据第一行包含一个整数 n(1≤n≤2⋅105) ,表示有其中 n 天是有人来的。

第二行包含 n 个用空格分开的整数 a1,a2,⋯,an(1=a1<a2<⋯<an≤2⋅105) ,表示 n 个有人来的日期。

输出格式

输出一行包含一个整数,表示需要的最少小朋友数量。

样例

Input

3
1 2 3

Output

1

Input

4
1 4 5 7

Output

2

提示

样例解释

对于第一个样例,我们只需要一个小朋友,每天都来。

对于第二个样例,我们至少需要两个小朋友,分别间隔 3 、 4 天来。


官方题解

考虑如果有小朋友在 x 天来了图书馆。

  • 可能他是每间隔 x−1 天来一次图书馆,于是所有日期为 y 且满足 y−1≡0(modx−1) 的日期都可以由他产生,故不再考虑这些天;

  • 如果他不是每间隔 x−1 天来一次图书馆,那么他的间隔只能更小,假设他的间隔为 a ,一定有 a|(x−1) ,这样一来,他一定在第 a+1 天的时候来了图书馆,那个时候我们已经可以知道不用再对 x 天考虑了,所以不可能存在这样的情况。

于是,我们只需要从小到大依次考虑没有被标记过(不用再考虑)的天数,并从标记他所能取消的天数就可以了。

这样有两种方式维护,一种是对每个天数判断他的约数是否已经存在,时间复杂度 O(n√n) ;

也可以用类似于筛法求质数那样做,时间复杂度 O(nlogn) 。

可能需要特判 n=1 的情况。


附代码,思路采取第一种方式

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

int a[200007];
int v[200007];

bool ex(int a){
	for(int i = 1;i<=sqrt(a);i++){
		if(a%i==0&&(v[i]||v[a/i])) return true;
	}
	return false;
}

int main(){
	int n,ans = 0;
	
	scanf("%d",&n);
	for(int i = 0;i < n;i++){
		scanf("%d",&a[i]);
	}
	int j = 1;
	while(j < n){
		while(!a[j]&&j < n) j++;
		if(ex(a[j]-1)) a[j] = 0;
		if(a[j]){
			v[a[j]-1] = 1;
			ans++;
		}
		j++;
	}
	if(!ans) printf("1\n");
	else printf("%d\n",ans);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值