题目
题意: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);
}
}