B - Prime Independence(质因子分解+HK)

题目
在这里插入图片描述题意:a * 一个质数=b,则a,b有关系。给你n个数,求出没关系的一个最大团。
想办法转化成二分图做。sigma(质因子指数)的奇偶来建图。因为*一个质数,sigma(质因子指数)+1,奇偶性发生变化。
如何找出这么多关系呢,难道要对一个数来讲,对所有质因子一个一个的乘除看谁在里面吗!!绝对TLE。那我们就对于每一个数,把他的所有质因子都除1遍,看可不可以找到一个数乘以这个质因子=这个数。每个数的质因子个数很有限,复杂度变低很多很多。
卡匈牙利,用HK,感觉也卡我的dinic???

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define sd(a) scanf("%d",&a)
#define foru(i,a,b) for(int i=a;i<=b;++i)
#define m(a,b) memset(a,b,sizeof a)
#define en '\n'
using namespace std;
typedef long long ll;
const int M=5e5+5,N=4e4+5,INF=0x3f3f3f3f;
struct Edge{int to,nex;}edge[N*10];
int mt[N],d[N],head[N];
int tot,dis,n;
int vis[N];
void add(int from,int to){
    edge[++tot]=(Edge){to,head[from]};head[from]=tot;
}
int dd[N][12],o1,o2,pos[M],a[N];
queue<int>q;
bool searchP()
{
    while(!q.empty()) q.pop();
    for(int i=1;i<=n;++i) d[i]=0;
    dis=INF;
    for(int i=1;i<=o1;i++)
        if(!mt[i]) q.push(i);
    while(!q.empty())
    {
        int x=q.front();q.pop();
        if(d[x]>dis) break;
        for(int i=head[x];i;i=edge[i].nex)
        {
            int y=edge[i].to;
            if(!d[y])
            {
                d[y]=d[x]+1;
                if(!mt[y]) dis=d[y];
                else d[mt[y]]=d[y]+1,q.push(mt[y]);
            }
        }
    }
    return dis!=INF;
}
bool dfs(int x)
{
    for(int i=head[x];i;i=edge[i].nex)
    {
        int y=edge[i].to;
        if(!vis[y]&&d[y]==d[x]+1)
        {
            vis[y]=1;
            if(mt[y]&&d[y]==dis) continue;
            if(!mt[y]||dfs(mt[y]))
            {
                mt[x]=y,mt[y]=x;
                return 1;
            }
        }
    }
    return 0;
}
int is[M],prime[M],cnt=0;
void get_prime()
{
    is[1]=1;
    for(int i=2;i<=M-5;++i)
    {
        if(!is[i]) prime[++cnt]=i;
        for(int j=1;(ll)i*prime[j]<=M-5&&j<=cnt;++j)
        {
            is[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
}
void solve(int x,int id)
{
    int tmp=x;
    for(int i=1;i<=10;++i) dd[id][i]=0;
    int num=0,sum=0;
    for(int i=1;(ll)prime[i]*prime[i]<=x&&i<=cnt;++i)
    {
        int flag=0;
        while(x%prime[i]==0) x/=prime[i],++flag;
        if(flag) sum+=flag,dd[id][++num]=prime[i];//a[id]的所有质因子储存
    }
    if(x>1) dd[id][++num]=x,++sum;//sum是a[id]=sigma(质因子的指数]).
    if(sum&1) pos[tmp]=--o2;//+ - 标记是二分图的哪一部分
    else pos[tmp]=++o1;
}
void make_graph()
{
    for(int i=1;i<=n;++i)
    {
        for(int j=1;dd[i][j];++j)
        {
            int tmp=pos[a[i]/dd[i][j]];//a[i]除以一个质因子看这个数是否存在
            if(tmp)
            {
                if(tmp>0) add(tmp,o1-pos[a[i]]);
                else add(pos[a[i]],o1-tmp);
            }
        }
    }
}
int main()
{
    get_prime();
    int T,cas=0;sd(T);
    while(T--)
    {
        for(int i=1;i<=o1;++i) head[i]=0;
        tot=1,o1=o2=0;
        for(int i=1;i<=M-5;++i) pos[i]=0;
        sd(n);
        foru(i,1,n) sd(a[i]),solve(a[i],i);
        make_graph();
        for(int i=1;i<=n;++i) mt[i]=0;
        int ans=0;
        while(searchP())//HK
        {
            for(int i=1;i<=-o2;++i) vis[o1+i]=0;
            for(int i=1;i<=o1;i++)
                if(!mt[i]&&dfs(i))
                    ans++;
        }
        printf("Case %d: %d\n",++cas,n-ans);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值