题意:给你一组数,求一个最大的子集,要求任意两个的倍数都不是素数倍
题解:将每一个数按照质因数奇偶分开,同为奇偶的肯定是合数倍,在奇偶中刚好是素数倍的建边,跑二分图最大独立集,n - 匹配数就是答案
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<set>
#include<vector>
using namespace std;
#define LL long long
#define INF 0x3f3f3f3f
#define eps 1e-10
const int MAXN = 4e4 + 10;
const int MOD = 1e9+7;
const int MAXX = 500005;
int prime[MAXX];
int num[MAXN],pos[MAXX];
int n;
void getprime(){
memset(prime,0,sizeof prime);
for(int i = 2; i <= MAXX; i++){
if(!prime[i]) prime[++prime[0]] = i;
for(int j = 1 ;j <= prime[0] && prime[j] <= MAXX / i; j++){
prime[prime[j] * i] = 1;
if(i % prime[j] == 0) break;
}
}
}
vector<int>G[MAXN];
int uN;
int Mx[MAXN],My[MAXN];
int dx[MAXN],dy[MAXN];
int dis;
bool used[MAXN];
void addedge(int u,int v) {
G[u].push_back(v);
}
bool SearchP(){
queue<int>que;
dis = INF;
memset(dx,-1,sizeof dx);
memset(dy,-1,sizeof dy);
for(int i = 1; i <= uN; i++){
if(Mx[i] == -1){
que.push(i);
dx[i] = 0;
}
}
while(!que.empty()){
int u = que.front();
que.pop();
if(dx[u] > dis) break;
int sz = G[u].size();
for(int i = 0; i < sz; i++) {
int v = G[u][i];
if(dy[v] == -1) {
dy[v] = dx[u] + 1;
if(My[v] == -1) dis = dy[v];
else {
dx[My[v]] = dy[v] + 1;
que.push(My[v]);
}
}
}
}
return dis != INF;
}
bool dfs(int u) {
int sz = G[u].size();
for (int i = 0; i < sz; i++) {
int v = G[u][i];
if(!used[v] && dy[v] == dx[u] + 1) {
used[v] = true;
if(My[v] != -1 && dy[v] == dis) continue;
if(My[v] == -1 || dfs(My[v])) {
My[v] = u;
Mx[u] = v;
return true;
}
}
}
return false;
}
int MaxMatch() {
int res = 0;
memset(Mx,-1,sizeof Mx);
memset(My,-1,sizeof My);
while(SearchP()) {
memset(used,false,sizeof used);
for (int i = 1; i <= uN; i++) {
if(Mx[i] == -1 && dfs(i)) res++;
}
}
return res;
}
int factor[105][2];
int fatcnt;
int sum;
int getFactors(int x) {
fatcnt = 0;
int tmp = x;
for (int i = 1; prime[i] <= tmp / prime[i]; i++) {
factor[fatcnt][1] = 0;
if (tmp % prime[i] == 0) {
factor[fatcnt][0] = prime[i];
while (tmp % prime[i] == 0) {
factor[fatcnt][1] ++;
tmp /= prime[i];
sum++;
}
fatcnt++;
}
}
if(tmp != 1) {
factor[fatcnt][0] = tmp;
factor[fatcnt++][1] = 1;
sum++;
}
return fatcnt;
}
void init() {
uN = 0;
memset(pos,0,sizeof pos);
for(int i = 0;i <= n; i++)
G[i].clear();
}
int main()
{
getprime();
int t;
scanf("%d",&t);
int ca = 1;
while(t--) {
init();
scanf("%d", &n);
uN = n;
for (int i = 1; i <= n; i++) {
scanf("%d", &num[i]);
pos[num[i]] = i;
}
for (int i = 1; i <= n; i++) {
sum = 0;
int pnum = getFactors(num[i]);
for(int k = 0; k < pnum; k++) {
if(pos[num[i] / factor[k][0]] != 0) {
if(sum & 1)
addedge(pos[num[i]],pos[num[i] / factor[k][0]]);
else
addedge(pos[num[i] / factor[k][0]], pos[num[i]]);
}
}
}
printf("Case %d: %d\n",ca++,n - MaxMatch());
}
}