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 3 2 3 2 2 5
其中 质因数 2 的次数出现的最多,出现了4 次, 所以我们只要删除 n-4=2 个数就能使最大公约数由1 变成 2 。即删除 a[1]和a[3]就好,答案就是 2 。
综上,只要找出质因数出现的最多的次数d, n-d就是我们要的答案。
代码实现过程中,由于数据较大,要把筛质数 和 选因子 分开来做, 不能同时筛质因子(会超时),因为要避免筛质数这部分重复(打一次表就好)。 筛质数的时候,用2000以内的质数就够了(我也不知道为什么!)
顺便一提:一个数m 的因子个数k 是小于log2m的 , 因为2^k<m 。 还有 数组至少能开1.5e7 大 。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include <cctype> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 #include<string> 8 #include<cmath> 9 #include<set> 10 #include<vector> 11 #include<stack> 12 #include<queue> 13 #include<map> 14 using namespace std; 15 #define ll long long 16 #define mem(a,x) memset(a,x,sizeof(a)) 17 #define se second 18 #define fi first 19 const ll mod=1e9+7; 20 const int INF= 0x3f3f3f3f; 21 const int N=3e5+5; 22 23 24 const int N2=1.5e7+5; 25 int n; 26 int cnt=0; 27 int check[2005]; 28 int a[N]; 29 int num[N2]; 30 int prime[N]; 31 32 33 int gcd(int x, int y) 34 { 35 return y==0?x:gcd(y,x%y); 36 } 37 void _prime() 38 { 39 int m=2000; 40 for(int i=2;i<=m;i++) //N以内的质数 41 { 42 if(!check[i]) 43 { 44 prime[++cnt]=i; 45 for(int j=i;j<=m;j+=i) 46 { 47 check[j]=1; 48 } 49 } 50 } 51 } 52 void factor(int m) 53 { 54 for(int i=1;i<=cnt;i++) 55 { 56 if(m%prime[i]==0) 57 num[prime[i] ]++; 58 while(m%prime[i]==0) 59 { 60 m/=prime[i]; 61 } 62 } 63 if(m!=1) //包括了1 64 num[m]++; 65 } 66 67 int main() 68 { 69 cin>>n; 70 for(int i=1;i<=n;i++) 71 scanf("%d",&a[i]); 72 73 int g=a[1]; //g=删除前的最大公约数 74 for(int i=2;i<=n;i++) g=gcd(g,a[i]); 75 76 _prime(); 77 for(int i=1;i<=n;i++) 78 { 79 a[i]/=g; 80 factor(a[i]); 81 } 82 83 int ans=INF; 84 for(int i=1;i<=N2;i++) 85 { 86 if(num[i]) 87 ans=min(ans,n-num[i]); 88 } 89 cout<< (ans<n? ans:-1 )<<endl; 90 }