问题 G: 集合划分(并查集运用+数论知识)

问题 G: 集合划分(并查集运用+数论知识)

题目描述

给定一个长度为 n 的正整数序列 {ai }。
将 {1,2,…,n} 划分成两个非空集合 S,T,使得 gcd(Π i∈S ai, Π j∈T aj)=1。
求划分方案数,对10 9+7 取模。

输入

第一行,一个非负整数t,代表数据组数。
每组数据的第一行,一个正整数n。
第二行,n个正整数,代表ai。

输出

输出t行,每行一个非负整数,代表答案对10 9+7取模的结果。

样例输入 Copy

3
3
2 3 1
3
2 3 6
4
2 3 6 1

样例输出 Copy

6
0
2

提示

对于100%的数据,n≤10 5,ai≤10 6,t≤5。
思路:题意很明显,但是不好写。我先TLE,再MLE。
后来,是直接把每个素数因子出现的id推进去,再并查集合并。
看代码吧。
#pragma GCC optimize(4)

#include <bits/stdc++.h>

#define rep(i , a , b) for(register int i=(a);i<=(b);i++)
#define per(i , a , b) for(register int i=(a);i>=(b);i--)


using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll , ll> pi;
typedef unordered_map<int,int> un_map;
template<class T>
inline void read (T &x) {
    x = 0;
    int sign = 1;
    char c = getchar ();
    while (c < '0' || c > '9') {
        if ( c == '-' ) sign = - 1;
        c = getchar ();
    }
    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar ();
    }
    x = x * sign;
}
const int maxn = 1e6 + 10;
const int inf = int (1e9);
const ll INF = ll(1e18);
const int mod = 1e9+7;

int n;
int vis[maxn],id[maxn];
int prime[78500],x;
std::vector<int> v[100005];
int fa[100005];

int Find(int u) {
    if(u==fa[u]) return fa[u];
    return fa[u] = Find(fa[u]);
}

void oulasai(){
    rep(i,2,maxn-5){
        if(!vis[i]) prime[++x]=i,vis[i]=i,id[i]=x;
        rep(j,1,x){
            if(i*prime[j]>maxn-5) break;
            vis[i*prime[j]]=prime[j];
            if(i%prime[j]==0) break;
        }
    }
}

ll qpow(ll a,ll b) {
    ll ans = 1;
    while(b) {
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}

bool visit[100005];

void solve(){
    memset(visit,0,sizeof(visit));
    read(n);
    int cnt = 0;
    rep (i,1,n) {
        fa[i]=i;
        int a;
        read(a);
        int m = a;
         while (m > 1){
             v[id[vis[m]]].push_back(i);
             int y = vis[m];
             while (m % y == 0) m /= y;
        }
    }
    rep(i,1,x) {
        int siz = v[i].size();
        rep(j,1,siz-1) {
            int uu = Find(v[i][j - 1]);
            int vv = Find(v[i][j]);
            if (uu != vv) fa[uu] = vv;
        }
    }
    rep(i,1,n) {
        int tmp = Find(i);
        if(!visit[tmp]) {
            cnt++;
            visit[tmp]=1;
        }
    }
    ll ans = (qpow(2,cnt)-2+mod)%mod;
    printf("%lld\n",ans);
    rep(i,1,x) v[i].clear();
}
int main () {
    //freopen("A.txt","r",stdin);
    oulasai();
    int t;
    scanf("%d",&t);
    while(t--) {
        solve();
    }
    //cout<<"over"<<endl;
    return 0;
}
发布了259 篇原创文章 · 获赞 2 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/dy416524/article/details/105733994