Time Limit: 3 second(s) | Memory Limit: 32 MB |
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} or {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 | Output for Sample Input |
3 5 2 4 8 16 32 5 2 3 4 6 9 3 1 2 3 | 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.
题意
找出一些数字的最大质独立集,就是集合能的所有数互相之间不会出现 a[i]==t*a[j] (t是质数) 的情况。
题解
首先想最大独立集对于一般图是NP问题,通常只有求二分图最大独立集,然后就是如何把这些数字分为二分图。
能够想到如果一个数字等于另一个数字乘以一个质数,那么这两个数字的质因子分解应该只有这一个质数的差别。也就是只会多一个质数,数字上限只有500000,完全可以看一个数组储存某个数字是否存在,然后对每个数字分解质因子,找到他对于每个质因子能够找到的那个数,存在则加边,然后就把质因子是奇数与偶数的分成两边并且把只有一个质因子差别的连通,然后二分图匹配求最大独立集即可。
关于二分图匹配因为数量较大所以用匈牙利会tle,要用Hopcroft-Carp:
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e4+10;
const int INF = 0x3f3f3f3f;
vector<int> G[maxn];
/// mx 是 左边点集所匹配的右边的点 ,同理 my 是 右边点集所匹配的左边的点集,dx是源点到x点集的距离,dy是源点到y点集的距离。
int mx[maxn],my[maxn],dx[maxn],dy[maxn];
bool vis[maxn];
int cntx,cnty;
int dis;
bool SearchPath() {
dis = INF;
//bool flag = false;
queue<int> qu;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=1;i<=cntx;i++)if(mx[i] == -1) { /// 以左点集(未匹配的点)作为源点集,
qu.push(i);dx[i] = 0;
}
while(!qu.empty())
{
int u = qu.front();qu.pop();
if(dx[u] > dis) break;
for(int i=0;i<G[u].size();i++) {
int to = G[u][i];
if(dy[to] == -1) { /// 如果to还没有访问到
dy[to] = dx[u] + 1;
if(my[to] != -1) { ///如果to已经有了匹配的对象
dx[my[to]] = dy[to] + 1; /// 距离加1
qu.push(my[to]); /// 将to的对象加入队列.
}
else dis = dy[to]; ///to没有匹配的对象,则找到了增广路.
//else flag = true;
}
}
}
return flag;
}
bool dfs(int u) { /// 类似与匈牙利的find函数
for(int i=0;i<G[u].size();i++) {
int to = G[u][i];
if(!vis[to] && dy[to] == dx[u] + 1) ///这里不同,只需要距离为1的匹配。
{
vis[to] = true;
if(my[to]!=-1 &&dy[to] == dis)continue;
if(my[to]==-1||dfs(my[to])) { /// 如果to没有匹配,或者to的匹配节点还能找到另一个匹配.
mx[u] = to; /// 改变匹配关系。
my[to] = u;
return true;
}
}
}
return false;
}
int MaxMatch() {
int ans = 0;
memset(mx,-1,sizeof(mx));
memset(my,-1,sizeof(my));
while(SearchPath()) /// search the path
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=cntx;i++) { /// dfs is match
if(mx[i] == -1 && dfs(i)) ans++;
}
}
return ans;
}
bool isprime[10*maxn];
vector<int> primes;
void creatprimes() {
memset(isprime,true,sizeof(isprime));
primes.clear();
isprime[0] = isprime[1] = 0;
for(int i=2;i<10*maxn;i++) {
if(isprime[i]) primes.push_back(i);
for(int j=0;j<primes.size() && primes[j]*i < 10*maxn;j++) {
isprime[primes[j]*i] = 0;
if(i % primes[j] == 0) break;
}
}
}
int arr[maxn],id[maxn];
int pos[10*maxn];
int divs[maxn];
void solve(int x,int now) {
int cnt = 0,tot = 0;
int tt = x;
for(int i=0;i<primes.size() && primes[i]*primes[i] <= tt;i++) if(tt % primes[i] == 0){
divs[cnt++] = primes[i];
while(tt%primes[i]==0) {
tt /= primes[i];
tot++;
}
}
if(tt > 1) divs[cnt++] = tt, tot++;
if(tot & 1) id[now] = ++cntx;
else id[now] = ++cnty;
for(int i=0,temp;i<cnt;i++) {
temp = x / divs[i];
if(pos[temp]) {
if(tot & 1) G[id[now]].push_back(id[pos[temp]]);
else G[id[pos[temp]]].push_back(id[now]);
}
}
}
inline void init() {
for(int i=0;i<maxn;i++) G[i].clear();
memset(pos,0,sizeof(pos));
memset(id,0,sizeof(id));
cntx = cnty = 0;
}
int main()
{
creatprimes();
int caset,cas=0;scanf("%d",&caset);
while(caset--) {
init();
int n;scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&arr[i]);
sort(arr+1,arr+1+n);
for(int i=1;i<=n;i++) pos[arr[i]] = i;
for(int i=1;i<=n;i++) solve(arr[i],i);
printf("Case %d: %d\n",++cas,n-MaxMatch());
}
return 0;
}