1. 程式人生 > >【CodeForces - 1034A】Enlarge GCD

【CodeForces - 1034A】Enlarge GCD

@Enlarge [email protected]


@題目描述 - [email protected]

time limit per test: 1 second
memory limit per test: 256 megabytes

Mr. F has n 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 himself. If you help him, he will give you some scores in reward.

Your task is to calculate the minimum number of integers you need to remove so that the greatest common divisor of the remaining integers is bigger than that of all integers.

Input
The first line contains an integer n (2≤n≤3⋅10^5) — the number of integers Mr. F has.
The second line contains n integers, a1,a2,…,an (1≤ai≤1.5⋅10^7).

Output
Print an integer — the minimum number of integers you need to remove so that the greatest common divisor of the remaining integers is bigger than that of all integers.
You should not remove all of the integers.
If there is no solution, print «-1» (without quotes).

Examples

input
3
1 2 4
output
1

input
4
6 9 15 30
output
2

input
3
1 1 1
output
-1

Note
In the first example, the greatest common divisor is 1 in the beginning. You can remove 1 so that the greatest common divisor is enlarged to 2. The answer is 1.

In the second example, the greatest common divisor is 3 in the beginning. You can remove 6 and 9 so that the greatest common divisor is enlarged to 15. There is no solution which removes only one integer. So the answer is 2.

In the third example, there is no solution to enlarge the greatest common divisor. So the answer is −1.

@中文題意@

n個數,要你刪掉最少的數,使得剩下的數的gcd大於所有n個數的gcd。
n<=3*10^5, 1<=ai<=1.5*10^7

@分析@

我們先用cnt[i]表示a裡面有多少個數等於i。

把所有的數都除以它們的gcd,則問題變為:保留最多的數,使得它們的gcd不等於1。假設所有數都等於1,顯然無解。假設某一數不等於1,則單獨選擇這一個數就是一個解, 所以一定有解。我們列舉保留下來的數的gcd為p,則可以保留下來的個數為 f ( p ) = p x x &lt; = 1.5 1 0 7 c n t [ x ] f(p)=\sum_{p|x}^{x&lt;=1.5*10^7}cnt[x]

可以發現 f ( p ) &gt; = f ( p a ) f(p)&gt;=f(p*a) ,因此我們列舉gcd的時候可以只列舉質數。可以通過線性篩將所有的質數 O ( n ) O(n) 時間複雜度篩出來

@時間複雜度分析@

【其實這道題很簡單來著……主要是在這個時間複雜度分析】
看起來,你枚舉了gcd,再枚舉了gcd的倍數來求解,所以是 O ( n 2 ) O(n^2) 的演算法。
但其實,假設列舉p的所有倍數,我們需要 O ( n / p ) O(n/p) 的時間。實際上時間複雜度為 O ( n / 1 + n / 2 + . . . . + n / n ) O(n/1+n/2+....+n/n) 。我們知道上式等於 O ( n l o g n ) O(nlogn) ,所以時間複雜度理應是 O ( n l o g n ) O(nlogn) 的。
進一步地,平均下來每一個數需要 O ( l o g n ) O(logn) 的時間。由素數定理可知:在[1, n]之間,質數個數趨近於 O ( n / l o g n ) O(n/logn) ,所以總時間複雜度為 O ( n ) O(n)

沒想到吧!看起來一個 O ( n 2 ) O(n^2) 的演算法其實是 O ( n ) O(n) 的qwq!

@程式碼@

【一場上藍,兩場上紫】
【太爽了啊哈哈哈哈哈哈OuO(被打)】
如果有什麼疑問或者想要Hack我的(不你們不可以Hack!),可以留言在下面,我會盡力替你們解疑的QwQ

#include<cstdio>
const int MAXM= 15000000;
const int MAXN = 300000;
bool Is_prm[MAXM + 5];
int prm[MAXM + 5], pcnt = 0;
void Sieve() {
	for(int i=2;i<=MAXM;i++) {
		if( !Is_prm[i] )
			prm[++pcnt] = i;
		for(int j=1;1LL*i*prm[j]<=MAXM;j++) {
			Is_prm[i*prm[j]] = true;
			if( i % prm[j] == 0 ) break;
		}
	}
}
int gcd(int x, int y) {
	return y == 0 ? x : gcd(y, x%y);
}
int cnt[MAXM + 5], a[MAXN + 5];
int main() {
	Sieve(); int n;
	scanf("%d", &n);
	for(int i=1;i<=n;i++)
		scanf("%d", &a[i]);
	int g = a[1];
	for(int i=1;i<=n;i++)
		g = gcd(g, a[i]);
	for(int i=1;i<=n;i++)
		cnt[a[i]/g]++;
	if( cnt[1] == n ) {
		printf("%d\n", -1);
		return 0;
	}
	int ans = MAXM;
	for(int i=1;i<=pcnt;i++) {
		int tot = 0;
		for(int j=prm[i];j<=MAXM;j+=prm[i])
			tot += cnt[j];
		if( n - tot < ans ) ans = n - tot;
	}
	printf("%d\n", ans);
}

@[email protected]

就是這樣,新的一天裡,也請多多關照哦(ノω<。)ノ))☆.。