CF1034A Enlarge GCD

题意:给你\(n\)个数,去掉尽量少的数使得剩下数的\(gcd\)比原来的大,无解输出\(-1\)

题目意思很简洁,想理出来一个清晰的思路却花了不少时间......首先先计算出总的\(GCD\),然后再把每个数都除去这个\(GCD\),接下来的事情就得仔细考虑一下了。

设\(M=max\left\{a[i]\right\}\),则若枚举\(1-M\)内所有质数(显然枚举质数比合数优)并一一判断在\(1-n\)中整除它们的数字的个数,复杂度为\(O(\frac{nM}{log\,M})\)必须爆炸。当时想到这里就优化不下去了,于是凉凉。实际上有一种看似暴力的方法可以较优地解决这个问题:我们开一个数组\(b[i]\),并在每一个\(b[a[i]]\)的位置上加一,那么当我们枚举质数的时候将其所有倍数上的数组\(b\)的值加在一起就可以更新答案了。运行次数大概是\(\sum \limits_{i为质数且i \le M}\frac{M}{i}\),这东西收敛得比较快,所以复杂度可以接受。

代码如下:

#include<cstdio>
#include<iostream>
#define INF 1000000000
using namespace std;
const int N=3e5+10;
const int M=1.5e7+10;
int n,a[N],GCD,primes[M],v[M],cnt,num[M],sum,ans=INF,maxn;
inline int exgcd(int x,int y){int r;while(x&&y){r=x%y;x=y;y=r;}return x;}
inline void Primes_Table(){
    for(register int i=2;i<=M-10;i++){
        if(!v[i]){v[i]=i;primes[++cnt]=i;}
        for(register int j=1;j<=cnt&&i*primes[j]<=M-10;j++){
            if(v[i]<primes[j])continue;v[i*primes[j]]=primes[j];}
    }
}
int main(){
    Primes_Table();scanf("%d",&n);
    for(register int i=1;i<=n;i++)scanf("%d",&a[i]);
    GCD=a[1];for(register int i=2;i<=n;i++)GCD=exgcd(GCD,a[i]);
    for(register int i=1;i<=n;i++)a[i]/=GCD,maxn=max(maxn,a[i]);
    for(register int i=1;i<=n;i++)num[a[i]]++;
    for(register int i=1;i<=cnt;i++){sum=0;
        for(register int j=primes[i];j<=maxn;j+=primes[i])sum+=num[j];
        ans=min(ans,n-sum);}
    printf("%d\n",ans==n? -1:ans);return 0;
}

原文地址:https://www.cnblogs.com/ForwardFuture/p/9738837.html

时间: 2024-10-11 16:23:26

CF1034A Enlarge GCD的相关文章

C. Enlarge GCD Codeforces Round #511 (Div. 2)【数学】

题目: Mr. F has nn positive integers, a1,a2,-,an. He thinks the greatest common divisor of these integers is too small. So he wants to enlarge it by removing some of the integers. But this problem is too simple for him, so he does not want to do it by

Codeforces Round #511 (Div. 2)-C - Enlarge GCD (素数筛)

传送门:http://codeforces.com/contest/1047/problem/C 题意: 给定n个数,问最少要去掉几个数,使得剩下的数gcd 大于原来n个数的gcd值. 思路: 自己一开始想把每个数的因子都找出来,找到这些因子中出现次数最多且因子大于n个数的最大公约数的,(n - 次数 )就是答案.但是复杂度是1e9,差那么一点. 自己还是对素数筛理解的不够深.这道题可以枚举素数x,对于每个x,找到所有(a[i]/gcd(all)) 是x倍数的个数,就是一个次数.找这个次数的过程

CF 1047 C. Enlarge GCD

传送门 [http://codeforces.com/contest/1047/problem/C] 题意 给你n个数,移除最少的数字是剩下的数字GCD大于初始GCD 思路 需要一点暴力的技巧,先求出初始GCD为g,并统计每个数字的个数这是减少复杂度的关键,令ans=0,我们从i=g+1开始枚举GCD为i的个数,进行统计每次更新ans=min(ans,n-cnt) 需要注意的是某个数的因子依然是那个数倍数的因子,如2 4 8.这样可以避免重复统计.具体看代码 代码 #include<bits/s

Codeforces Round #511 (Div. 2) C. Enlarge GCD (质因数)

题目 题意: 给你n个数a[1]...a[n],可以得到这n个数的最大公约数, 现在要求你在n个数中 尽量少删除数,使得被删之后的数组a的最大公约数比原来的大. 如果要删的数小于n,就输出要删的数的个数, 否则输出 -1 . 思路: 设原来的最大公约数为 g, 然后a[1]...a[n]都除以g ,得到的新的a[1]...a[n],此时它们的最大公约数一定是1 . 设除以g之后的数组a为: 1    2    3     6      8   10  则它们的质因数分别是:  1    2   

CodeForces 1047C Enlarge GCD(数论)题解

题意:n个数的gcd是k,要你删掉最少的数使得删完后的数组的gcd > k 思路:先求出k,然后每个数除以k.然后找出出现次数最多的质因数即可. 代码: #include<cmath> #include<set> #include<map> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include <iostream

CF#511-C Enlarge GCD(gcd)

题意:给你一个序列,然后求删除几个数之后整个序列的最大公约数增大思路:我们首先要求出这个公共的gcd,然后要使gcd增大我们可以尝试对增加gcd并判断是否为存在某个数为该数的gcd同时统计个数,为公共gcd最大的即为最后所求的值.(增加上限就是到最大的那个数)范围为1~1e5,arr[i]为1.5e7 完整代码: #include <cstdio> #include <cstring> #include <cmath> #include <algorithm>

Codeforces Round #511 (Div. 2) C. Enlarge GCD

题目链接 题目就是找每个数的最小素因子,然后递归除,本来没啥问题,结果今天又学习了个新坑点. 我交了题后,疯狂CE,我以为爆内存,结果是,我对全局数组赋值, 如果直接赋值,会直接在exe内产生内存,否则只会在运行时才分配内存. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 1e7 + 5e6 + 10; 5 6 //线性素数筛 7 int prime[2000000],num_prime = 0;

Codeforces Round #511 Div2 C. Enlarge GCD

http://codeforces.com/contest/1047/problem/C 问题 给一个序列 \(A\),计原序列所有数的最大公约数为 \(p\).现在要删除一些数形成一个新序列,计新序列所有数的最大公约数为 \(q\) 问最少删除多少数能使 \(q > p\). 题解 先求出 \(p\),然后枚举 \(q > p\),计算一下序列中 \(q\) 的倍数有哪些.注意到若存在 \(a | q\) 且 \(a > p\),那么 \(a\) 显然优于 \(p\),因此用一个类似筛

Codeforces Round #511 (Div. 2)

又到了摸鱼的时候了23333 A. Little C Loves 3 I 题意:给一个数,分解为不被3整除的3个数 题解:构造,如果这个数被3整除,就构造为1,1,n-2:否则构造为1,2,n-3 1 class Solution(object): 2 def run(self): 3 n = int(input()) 4 if n % 3 == 0: 5 print(1, 1, n - 2) 6 else: 7 print(1, 2, n - 3) 8 9 if __name__ == '__