【莫比乌斯反演】CodeForces 1043F Make It One

S o u c e : Souce: Souce: Codeforces Round #519 by Botan Investments
P r o b l e m : Problem: Problem:给n个数(n<=3e5),每个数<=3e5,选择最少的数,使得他们的gcd为1。输出这个最小子集的大小。
I d e a : Idea: Idea:可以二分,或者直接枚举,因为2 * 3 * 5 * 7 * 11 * 13 * 17 > 3e5,每次选择会删去一个素数,所以答案不超过7。接着用莫比乌斯反演验证答案是否存在,g(x,len)表示集合大小为len,gcd为x的倍数的方案数,那么验证f(1, len)的方案数不为0即可。
C o d e : Code: Code:

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 3e5+10;
const int MOD = 1e9+7;

bool isn[N];
int mu[N], p[N];
LL inv[N], fac[N];

void init() {
    inv[1] = 1;
    for(int i = 2; i < N; ++i) inv[i] = MOD-(MOD/i*inv[MOD%i]%MOD);
    fac[0] = 1, inv[0] = 1;
    for(int i = 1; i < N; i++){
        fac[i] = fac[i-1]*i%MOD;
        inv[i] = inv[i-1]*inv[i]%MOD;
    }
    int pnt = 0;
    isn[1] = 1; mu[1] = 1;
    for(int i = 2; i < N; i++) {
        if(!isn[i]) { p[pnt++] = i; mu[i] = -1; }
        for(int j = 0; j<pnt && i*p[j]<N; j++) {
            isn[i*p[j]] = 1;
            if(i%p[j] == 0) { mu[i*p[j]] = 0; break; }
            mu[i*p[j]] = -mu[i];
        }
    }
}

inline LL C(int a, int b) { return fac[a]*inv[b]%MOD*inv[a-b]%MOD; }

int cnt[N];

int main() {
    init();
    int n, g; scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        int x; scanf("%d", &x);
        if(i == 1) g = x;
        else g = __gcd(g, x);
        cnt[x]++;
    }
    if(g != 1) { puts("-1"); exit(0); }
    for(int i = 1; i < N; i++)
    for(int j = i+i; j < N; j += i)
        cnt[i] += cnt[j];
    for(int i = 1; i <= min(n, 7); i++) {
        LL sum = 0;
        for(int j = 1; j < N; j++) if(cnt[j] >= i) {
            (sum += mu[j]*C(cnt[j], i)) %= MOD;
        }
        if(sum) { printf("%d\n", i); break; }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值