C. Enlarge GCD(内存的限制 + 数组的访问速度)

Problem - C - Codeforces

Mr. F 有 n 个正整数 a1,a2,…,an。

他认为这些整数的最大公约数太小了。所以他想通过删除其中一些整数来扩大它。

但是这个问题对他来说太简单了,所以他不想自己做。如果你帮他解决这个问题,他会给你一些奖励分数。

你的任务是计算您需要删除的最少数量的整数,以便剩余整数的最大公约数大于所有整数的最大公约数。

输入 第一行包含一个整数 n (2≤n≤3⋅105) — Mr. F 拥有的整数数量。

第二行包含 n 个整数 a1,a2,…,an (1≤ai≤1.5⋅107)。

输出 请输出一个整数 — 您需要删除的最少数量的整数,以便剩余整数的最大公约数大于所有整数的最大公约数。

您不应该删除所有整数。

如果没有解决方案,请输出 "-1"(不要引号)。

Examples

input

Copy

3
1 2 4

output

Copy

1

input

Copy

4
6 9 15 30

output

Copy

2

input

Copy

3
1 1 1

output

Copy

-1

 

在第一个例子中,最大公约数一开始为1。你可以去掉1,使得最大公约数变成2。答案是1。

在第二个例子中,最大公约数一开始为3。你可以去掉6和9,使得最大公约数变成15。没有只去掉一个整数就能实现的解决方案。因此答案是2。

在第三个例子中,没有办法扩大最大公约数。因此答案是-1。

题解:
对于有很多数据的题目尽量不用map,用数组进行操作,

一般来说,题目给的内存限制,只够我们开到2e7的数组

对于不是太大的输入输出,如果超时,可能时#define int long long的原因

对于本题来说,首先线性筛筛质数,

每个数/数组的最大公约数,记录剩下数中都含有什么因子,

含有的因子最多的便是我们应该保留的数目

注意特判,数组中数全部相等的情况

#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define int long long
typedef pair<int,int> PII;
const int N = 1.5e7 + 10;
int mod = 1e9 + 7;
int pri[N/10];
int vis[N];
int a[300050]; 
int c[N];
void solve()
{
	int n;
	scanf("%d",&n);
	int cnt = 0;
	for(int i = 2;i <= N - 10;i ++)
	{
		if(!vis[i])
		{
			pri[++cnt] = i;
		}
		for(int j = 1;j <= cnt&&i*pri[j] <= N;j++)
		{
			vis[i*pri[j]] = 1;
			if(i%pri[j] == 0)
			break;
		}
	}
	int g = 0;
	for(int i = 1;i <= n;i++)
	{
		scanf("%d",&a[i]);
		g = __gcd(a[i],g);
	}
	for(int i = 1;i <= n;i++)
	{
		a[i] /= g;
		for(int j = 1;pri[j]*pri[j] <= a[i];j++)
		{
			if(a[i]%pri[j] == 0)
			{
				c[pri[j]]++;
				while(a[i]%pri[j] == 0)
				{
					a[i] /= pri[j];
				}
			}
		}
		if(a[i] > 1)
		c[a[i]]++;
	}
	int ans = 1e9;
	for(int i = 1;i <= N - 10;i++)
	{
		ans = min(ans,n - c[i]);
	}
	if(ans == n)
	{
		printf("-1");
	}
	else
	{
		printf("%d",ans);
	}
}

signed main()
{
//	ios::sync_with_stdio(0 );
//	cin.tie(0);cout.tie(0);
	int t = 1;
//	cin >> t;
	while(t--)
	{
		solve(); 
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值