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\),因此用一个类似筛法的方法枚举就好了,复杂度 \(O(N \cdot \log{\log{N}})\)

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int, int> pii;

int rint() {
    int n, c, sgn = 0;
    while ((c = getchar()) < '-');
    if (c == '-') n = 0, sgn = 1;
    else n = c - '0';
    while ((c = getchar()) >= '0') {
        n = 10 * n + c - '0';
    }
    return sgn ? -n : n;
}

const int N = 300010;
const int MAX = 1.5e7 + 10;

int n;
bool mark[MAX];
int cnt[MAX];

int main() {
    scanf("%d", &n);
    int g = 0;
    for (int i = 0; i < n; i++) {
        int x;
        scanf("%d", &x);
        cnt[x]++;
        g = __gcd(g, x);
    }

    int ans = n;
    for (int d = g + 1; d < MAX; d++) {
        if (mark[d]) continue;
        int need = 0;
        for (ll j = d; j < MAX; j += d) {
            mark[j] = true;
            need += cnt[j];
        }
        if (need > 0) {
            ans = min(ans, n - need);
        }
    }
    if (ans == n) puts("-1");
    else printf("%d\n", ans);

    fprintf(stderr, "%.3lf sec\n", double(clock()) / CLOCKS_PER_SEC);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hfccccccccccccc/p/9777475.html