A set of integers is called prime independent if none of its member is a prime multiple of another member. An integer a is said to be a prime multiple of b if,

a = b x k (where k is a prime [1])

So, 6 is a prime multiple of 2, but 8 is not. And for example, {2, 8, 17} is prime independent but {2, 8, 16}&nbs***bsp;{3, 6} are not.

Now, given a set of distinct positive integers, calculate the largest prime independent subset.

Input

Input starts with an integer T (≤ 20), denoting the number of test cases.

Each case starts with an integer N (1 ≤ N ≤ 40000) denoting the size of the set. Next line contains N integers separated by a single space. Each of these Nintegers are distinct and between 1 and 500000 inclusive.

Output

For each case, print the case number and the size of the largest prime independent subset.

Sample Input

3

5

2 4 8 16 32

5

2 3 4 6 9

3

1 2 3

Sample Output

Case 1: 3

Case 2: 3

Case 3: 2

Note

1.      An integer is said to be a prime if it's divisible by exactly two distinct integers. First few prime numbers are 2, 3, 5, 7, 11, 13, ...

2.      Dataset is huge, use faster I/O methods.


题目大意:给你n个数,定义:如果两个数 a,b 满足a*k=b  且k为素数,这时说 b为a的素数倍,求n个数中最多可以选出多少个数,使得两两互不为素数倍。

题目思路:

思路很简单,最大独立集的裸题,我们a 与b 如果有关系我们就建一条双向边,这里说一下,怎么建图:

首先我们把 n个数质因子分解,存储它的每一个质因子。最后对质因子进行判断,如果 当前数/质因子 这个数存在,就建立一条边。最后判断即可。

这个题把我wa飞了,最后质因子分解不对。

AC:

#include <bits/stdc++.h>
#include<stdio.h>
#include <string.h>
#include<algorithm>
#pragma GCC optimize(2)
typedef long long ll;
const int mod=998244353;
const int maxn=5e5+5;
const ll INF=10000000000000005;
using namespace std;
ll n,m,p,lm;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int prime[maxn];
bool vis[maxn];
int num[maxn];
int dR[maxn],dL[maxn];//增广路距离
int nR[maxn],nL[maxn];//左右标记
int used[maxn];//使用标记
int pos[maxn];
int head[maxn];
ll cnt=0,dis;
int save[40005];
struct node{
    int e,next;
}edge[maxn];
void addedge(int u,int v)
{
    edge[cnt]=node{v,head[u]};
    head[u]=cnt++;
}
bool judge()//寻找最短增广路
{
    queue<int>q;
    memset(dL,-1,sizeof(dL));
    memset(dR,-1,sizeof(dR));
    for(int i=1;i<=n;i++)
    {
        if(nL[i]==-1){
            q.push(i);
            dL[i]=0;
        }
    }
    dis=INF;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        if(dL[u]>dis) break;
        for(int i=head[u];~i;i=edge[i].next)
        {
            int e=edge[i].e;
            if(dR[e]==-1)//保证增广路不相交
            {
                dR[e]=dL[u]+1;
                if(nR[e]==-1) dis=dR[e];
                else{
                    dL[nR[e]]=dR[e]+1;
                    q.push(nR[e]);
                }
            }
        }
    }
    return dis!=INF;
}
bool Find(int x)
{
    for(int i=head[x];~i;i=edge[i].next)
    {
        int e=edge[i].e;
        if(dR[e]==dL[x]+1&&!used[e])
        {
            used[e]=1;
            if(nR[e]!=-1&&dis==dR[e]) continue;//优化
            if(nR[e]==-1||Find(nR[e]))
            {
                nR[e]=x;
                nL[x]=e;
                return true;
            }
        }
    }
    return false;
}
ll MaxMatch()
{
    int res=0;
    while(judge())
    {
        memset(used,0,sizeof(used));
        for(int i=1;i<=n;i++)
            if(nL[i]==-1&&Find(i)) res++;
    }
    return res/2;
}
void restart()
{
    vis[1]=true;
    for(int i=2;i<500005;i++)
    {
        if(!vis[i])
        {
            prime[++cnt]=i;
            for(int k=2*i;k<500005;k+=i)
                vis[k]=true;
        }
    }
}
int main()
{
    restart();
    int cas=0;
    int T;scanf("%d",&T);
    while(T--)
    {
        cnt=0;
        memset(nR,-1,sizeof(nR));
        memset(nL,-1,sizeof(nL));
        memset(pos,0,sizeof(pos));
        memset(head,-1,sizeof(head));
        scanf("%lld",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
            pos[num[i]]=i;
        }
        for(int i=1;i<=n;i++)
        {
            int x=num[i];
            int cot=0;
            for(int k=1;prime[k]*prime[k]<=x;k++)
            {
                int f=0;
                while(x%prime[k]==0)
                {
                    f=1;
                    x/=prime[k];
                }
                if(f) save[++cot]=prime[k];
            }
            if(x>1) save[++cot]=x;
            for(int k=1;k<=cot;k++)
            {
                int y=num[i]/save[k];
                if(pos[y])
                {
                    addedge(i,pos[y]);
                    addedge(pos[y],i);
                }
            }
        }
        int res=MaxMatch();
        res=n-res;
        printf("Case %d: %d\n",++cas,res);
    }
    return 0;
}
/***
4 2 2 1
0 2 10
2 3  20
0 2 5
2 3 14
***/

总结:幸运的是:他把我的HK模板给Hack了,又把我的HK模板优化了一次,写了三个小时,不亏!