Problem 5 素数筛法+并查集

$des$

给定一个长度为 $n$ 的正整数序列 ${a_i }$。
将 ${1,2,...,n}$ 划分成两个非空集合 $S、T$,使得 $gcd(\prod_{i \in S} a_i,
\prod_{i \in T} a_i) = 1$
求划分方案数,对 $10^9 + 7$ 取模。

$sol$

对于两个数 $a, b$ 必须处于同一个集合,当其含有相同因子。
这样的话,将含有相同因子的数用并查集维护。
最后统计所有的 $n$ 个数被分成了 $x$ 个集合
答案就是 $2 ^ n - 2$,$1$ 需要特判

#include <bits/stdc++.h>

using namespace std;

#define gc getchar()
inline int read() {
    int x = 0; char c = gc;
    while(c < '0' || c > '9') c = gc;
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
    return x;
}

#define Rep(i, a, b) for(int i = a; i <= b; i ++)
#define LL long long

const int N = 1e5 + 10, To = 1e6;

bool Check[To + 10];
int tot, prime[To];

int fa[To + 10];
int n;
int A[N];
bool Use[To];

void Get() {
    Rep(i, 2, To) {
        if(!Check[i]) prime[++ tot] = i;
        Rep(j, 1, tot) {
            if(prime[j] * i > To) break;
            Check[i * prime[j]] = 1;
            if(i % prime[j] == 0) break;
        }
    }
}

int Get(int x) {
    return fa[x] == x ? x : fa[x] = Get(fa[x]);
}

const int Mod = 1e9 + 7;

LL Ksm(LL a, LL b) {
    LL ret = 1;
    while(b) {
        if(b & 1) ret = ret * a % Mod;
        a = a * a % Mod;
        b >>= 1;
    }
    return ret;
}

int vis[To];

int main() {
    Get();
    for(int T = read(); T; T --) {
        n = read();
        int js = 0;
        memset(Use, 0, sizeof Use);
        int Max = 0;
        Rep(i, 1, n) A[i] = read(), Use[A[i]] = 1, Max = max(Max, A[i]), js += (A[i] == 1);
        Rep(i, 1, To) fa[i] = i;
        Rep(i, 1, tot) {
            if(prime[i] > Max) break;
            for(int j = 1; j * prime[i] <= Max; j ++) {
                int num = j * prime[i];
                if(Use[num]) {
                    int fa1 = Get(num), fa2 = Get(prime[i]);
                    if(fa1 != fa2) fa[fa1] = fa2;
                }
            }
        }
        LL up = 0;
        Rep(i, 1, n) {
            int f = Get(A[i]);
            if(vis[f] != T) vis[f] = T, up ++;
        }
        if(js > 1) up += (js - 1);
        LL ans = Ksm(2, up);
        ans -= 2;
        if(ans < 0) ans += Mod;
        cout << ans << "\n";
    }
    
    return 0;
}

 

posted @ 2018-10-11 08:08  xayata  阅读(232)  评论(0编辑  收藏  举报