题意:
对于给定集合,求解最大的子集合,使得集合内两两之商不为质数。
解法:
考虑对于每一个数字分解质因数可以得到 $O(nloglogNUM)$ 条两个数字不可以出现在同一集合的信息。
同时发现一条代表冲突的边必然是联结一个由奇数个质数连乘构成的数字和一个由偶数个质数连乘构成的数字。
是一个二分图,考虑最大独立集即可。
#include <bits/stdc++.h> const int N = 100010; using namespace std; int n,timnow; int pre[N],a[N],v[N],cnt[N],Id[500010]; vector<int> g[N],fac[N]; bool find(int x) { for(int i=0;i<(int)g[x].size();i++) { int p = g[x][i]; if(v[p] == timnow) continue; v[p] = timnow; if(!pre[p] || find(pre[p])) { pre[p] = x; return 1; } } return 0; } int main() { int T,Te = 0; scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) g[i].clear(),pre[i] = 0,fac[i].clear(),cnt[i]=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); Id[a[i]] = i; int tmp = a[i]; for(int j=2;j*j<=a[i];j++) if(tmp%j==0) { fac[i].push_back(j); while(tmp%j==0) tmp/=j, cnt[i]++; } if(tmp>1) fac[i].push_back(tmp), cnt[i]++; } for(int i=1;i<=n;i++) { for(int j=0;j<(int)fac[i].size();j++) { int tmp = a[i]/fac[i][j]; if(Id[tmp]) { int k = Id[tmp]; if(cnt[i]&1) g[i].push_back(k); else g[k].push_back(i); } } } int ans = 0; for(int i=1;i<=n;i++) { timnow ++; if(find(i)) ans++; Id[a[i]] = 0; } printf("Case %d: %d ", ++Te, n-ans); } return 0; }