Codeforces Round #511 (Div. 2) C. Enlarge GCD (質因數)
阿新 • • 發佈:2018-12-15
題意:
給你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 大 。
1 #include<iostream> 2 #include<cstdio> 3 #include <cctype> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 #include<string> 8 #include<cmath> 9View Code#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 }