Prime Independence(LightOJ - 1356,线性筛 + 最大独立集)

一.题目链接

\quad Prime Independence

二.题目大意

\quad n n n 个数, A A A 被称为 B B B 的素倍数当前仅当 A = B × P A = B \times P A=B×P P P P 为素数)

\quad 定义最大独立集为最多能选出多少个数,使得选出的数两两之间不存在素倍数关系.

\quad 求最大独立集.

\quad 1 ≤ N ≤ 1 0 4 , 1 ≤ e ≤ 5 × 1 0 5 1 \leq N \leq 10^4, 1 \leq e \leq 5 \times 10^5 1N104,1e5×105 e e e 两两不同.

三.分析

\quad 图论、数论两开花ヾ(✿゚▽゚)ノ

四.代码实现

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

namespace Graph
{
    
    
    const int M = (int)8e4;
    const int N = (int)1e5;
    const int inf = 0x3f3f3f3f;

    int n, m, S, T, cnt;
    int head[M + 5];

    struct node
    {
    
    
        int v, w, nx;
    }Edge[N * 2 + 5];

    int d[M + 5];
    int cur[M + 5];
    int q[M + 5], l, r;

    void init()
    {
    
    
        cnt = 0;
        for(int i = 0; i <= n; ++i)
        {
    
    
            head[i] = -1;
        }
    }

    void add(int u, int v, int w)
    {
    
    
        Edge[cnt].v = v;
        Edge[cnt].w = w;
        Edge[cnt].nx = head[u];
        head[u] = cnt++;
    }

    bool bfs()
    {
    
    
        l = 1, r = 0;
        for(int i = 1; i <= n; ++i) d[i] = -1;
        q[++r] = S, d[S] = 0, cur[S] = head[S];
        while(l <= r)
        {
    
    
            int u = q[l++];
            if(u == T) return 1;
            for(int i = head[u]; ~i; i = Edge[i].nx)
            {
    
    
                int v = Edge[i].v;
                if(d[v] == -1 && Edge[i].w)
                {
    
    
                    d[v] = d[u] + 1;
                    cur[v] = head[v];
                    q[++r] = v;
                }
            }
        }
        return 0;
    }

    int dfs(int u, int limit)
    {
    
    
        if(u == T) return limit;
        int flow = 0;
        for(int i = cur[u]; ~i && flow < limit; i = Edge[i].nx)
        {
    
    
            cur[u] = i;
            int v = Edge[i].v;
            if(d[v] == d[u] + 1 && Edge[i].w)
            {
    
    
                int t = dfs(v, min(Edge[i].w, limit - flow));
                if(!t) d[v] = -1;
                Edge[i].w -= t, Edge[i^1].w += t, flow += t;
            }
        }
        return flow;
    }

    int Dinic()
    {
    
    
        int r = 0, flow;
        while(bfs()) while(flow = dfs(S, inf)) r += flow;
        return r;
    }
};

namespace Math
{
    
    
    const int M = (int)5e5;

    bool is_prime[M + 5];
    int prime[M + 5], cnt;
    int v[M + 5];//最小质因子

    void init()
    {
    
    
        memset(is_prime, 1, sizeof(is_prime));
        is_prime[0] = is_prime[1] = 0;
        for(int i = 2; i <= M; ++i)
        {
    
    
            if(is_prime[i])
            {
    
    
                prime[++cnt] = i;
                v[i] = i;
            }
            for(int j = 1; j <= cnt && i * prime[j] <= M; ++j)
            {
    
    
                is_prime[i * prime[j]] = 0;
                v[i * prime[j]] = prime[j];
                if(i % prime[j] == 0)
                {
    
    
                    break;
                }
            }
        }
    }
};

typedef long long ll;

const int M = (int)4e4;
const int N = (int)4e4;
const int inf = 0x3f3f3f3f;
const ll mod = (ll)1e9 + 7;
const double eps = 1e-9;

int n, a[M + 5];
int n1, l[M + 5];
int n2, r[M + 5];
int fac[M + 5][10];
int len[M + 5];

int cal(int p)
{
    
    
    len[p] = 0;
    int x = a[p], c = 0;
    while(x > 1)
    {
    
    
        fac[p][++len[p]] = Math::v[x];
        x /= Math::v[x];
        ++c;
    }
    sort(fac[p] + 1, fac[p] + len[p] + 1);
    len[p] = unique(fac[p] + 1, fac[p] + len[p] + 1) - (fac[p] + 1);
    return c;
}

int bsl(int x)
{
    
    
    int L = 1, R = n1 + 1, mid;
    while(L < R)
    {
    
    
        mid = (L + R) >> 1;
        if(a[l[mid]] >= x) R = mid;
        else               L = mid + 1;
    }
    return R;
}

int bsr(int x)
{
    
    
    int L = 1, R = n2 + 1, mid;
    while(L < R)
    {
    
    
        mid = (L + R) >> 1;
        if(a[r[mid]] >= x) R = mid;
        else               L = mid + 1;
    }
    return R;
}

int main()
{
    
    
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
    Math::init();
    int T; scanf("%d", &T);
    for(int ca = 1; ca <= T; ++ca)
    {
    
    
        scanf("%d", &n); n1 = n2 = 0;
        for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        sort(a + 1, a + n + 1);
        for(int i = 1, c; i <= n; ++i)
        {
    
    
            c = cal(i);
            if(c & 1) l[++n1] = i;
            else      r[++n2] = i;
        }
        Graph::n = n1 + n2 + 1; Graph::init();
        for(int i = 1, x, y, p; i <= n1; ++i)
        {
    
    
            Graph::add(0, i, 1), Graph::add(i, 0, 0);
            for(int j = 1; j <= len[l[i]]; ++j)
            {
    
    
                y = a[l[i]] / fac[l[i]][j];
                p = bsr(y);
                if(p <= n2 && a[r[p]] == y) Graph::add(i, n1 + p, 1), Graph::add(n1 + p, i, 0);
            }
        }
        for(int i = 1, x, y, p; i <= n2; ++i)
        {
    
    
            Graph::add(n1 + i, n1 + n2 + 1, 1), Graph::add(n1 + n2 + 1, n1 + i, 0);
            for(int j = 1; j <= len[r[i]]; ++j)
            {
    
    
                y = a[r[i]] / fac[r[i]][j];
                p = bsl(y);
                if(p <= n1 && a[l[p]] == y) Graph::add(p, n1 + i, 1), Graph::add(n1 + i, p, 0);
            }
        }
        Graph::S = 0, Graph::T = n1 + n2 + 1;
        printf("Case %d: %d\n", ca, n1 + n2 - Graph::Dinic());
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/The___Flash/article/details/107804362