CodeFroces New Assignment 二分图匹配

There is a class consisting of n students, in which each one has a number representing his/her personality. The teacher gives the students a new assignment and asks them to solve it in groups so that each group can contain two students at most.

Students cannot create groups as they please because the teacher gives the following rules that must be met in order for a group to be valid:

  • The group can be‎由‎of one male student, one female student, or male and female students.
  • If the number of students in the group is two, these students must share common interests. Two students i and j share interests if and only if their numbers ai and aj share common divisor d > 1.

Since this is a really diverse class, no triple of students share a common interest, therefore all triples ai, aj, ak are co-primes (i.e. gcd(ai, aj, ak) ≡ 1).

Your task is to distribute the students into groups such that each student must join exactly one group, and the number of groups is as minimal as possible. Can you?

Input

The first line contains an integer T (1 ≤ T ≤ 100), in which T is the number of test cases.

The first line of each test case contains an integer n (1 ≤ n ≤ 104), in which n is the number of students in the class.

Then a line follows containing n integers a1, a2, ..., an (1 ≤ ai ≤ 106), in which ai if the personality of the ith student. Then a line follows containing n space-separated characters p1, p2, ..., pn (), in which pi is "M" if the ith student is male, and "F" if she is female.

‎ ‎‎n‎‎ ‎‎总测试用例的总和不超过‎ 3 × 105.

Output

For each test case, print a single line containing the minimum number of groups that can be formed in the class.

Example

Input
2
2
3 6
M F
5
5 6 7 10 21
F F F M M
Output
1
3

Note

In the second test case, the minimum number of groups is 3, in which the first group consists of the 1st and 4th students, the second group consists of the 2nd student, and the third group consists of the 3rd and 5th students.

 

思路:第一反应是二分图匹配找到最大匹配数,再看数据n有1e4,而且T有1e2,用匈牙利可能会超时,所以用网络流写法;再思考如何建图连边,暴力n²会超时,只能想如何优化建边了。

想到题目要求两人gcd > 1,所以把每个人对应的数字拆分质因数,我这里先将女生的数的质因数通过df函数(作用就是得出该数的所有质因数且不记录重复的质因数)放入vector数组k[素数(质因数)][i]=女生对应的编号,在通过同样意义的df'数组将男生的数分解质因数,此时不用保存在数组里了,可以直接吧有该质因数的vector数组里的女生连边。

这样就能建图然后利用网络流跑一遍最大匹配,用总数减去最大匹配数得到结果了。

注:vector数组k[素数][i]里的素数并不是直接对应的素数,因为a[i]最大有1e6,所以直接存会很浪费空间,于是首先用素数筛将素数全部找出并标号,k[i][j]的第一维表示的是第i个素数。

贴一发优化llw大佬后的代码

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<string>
  5 #include<vector>
  6 #include<cstdio>
  7 #include<cstdlib>
  8 #include<cmath>
  9 #include<queue>
 10 #include<map>
 11 #include<set>
 12 #include<stack>
 13 
 14 using namespace std;
 15 typedef long long ll;
 16 typedef unsigned long long ull;
 17 typedef pair<int,int> P;
 18 
 19 #define bug printf("*********\n");
 20 #define debug(x) cout<<"["<<x<<"]" <<endl;
 21 #define mid (l+r)/2
 22 #define chl 2*k+1
 23 #define chr 2*k+2
 24 #define lson l,mid,chl
 25 #define rson mid,r,chr
 26 #define pb push_back
 27 #define mem(a,b) memset(a,b,sizeof(a));
 28 
 29 const long long mod=998244353;
 30 const int maxn=1e6+5;
 31 const int INF=0x7fffffff;
 32 const int inf=0x3f3f3f3f;
 33 const double eps=1e-8;
 34 const double pi=acos(-1);
 35 
 36 
 37 struct edge {
 38     int to,cap,rev;
 39 };
 40 vector <edge> G[maxn];
 41 int level[maxn];
 42 int iter[maxn];
 43 
 44 void init(int _n) {
 45     for(int i=0; i<=_n; i++) {
 46         G[i].clear();
 47     }
 48 }
 49 
 50 void bfs(int s) {
 51     memset(level,-1,sizeof(level));
 52     queue<int> que;
 53     level[s]=0;
 54     que.push(s);
 55     while(!que.empty()) {
 56         int v= que.front();
 57         que.pop();
 58         for(int i=0; i<G[v].size(); i++) {
 59             edge & e=G[v][i];
 60             if(e.cap>0&&level[e.to]<0) {
 61                 level[e.to]=level[v] + 1;
 62                 que.push(e.to);
 63             }
 64         }
 65     }
 66 }
 67 
 68 void add(int from,int to,int cap) {
 69     edge eg;
 70     eg.to=to;
 71     eg.cap=cap;
 72     eg.rev=G[to].size();
 73     G[from].push_back(eg);
 74     eg.to=from;
 75     eg.cap=0;
 76     eg.rev=G[from].size()-1;
 77     G[to].push_back(eg);
 78 }
 79 
 80 int dfs(int v,int t,int f) {
 81     if(v == t)return f;
 82     for(int &i = iter[v]; i < G[v].size(); i++) {
 83         edge &e=G[v][i];
 84         if(e.cap>0 && level[v]<level[e.to]) {
 85             int d=dfs(e.to,t,min(f,e.cap));
 86             if(d>0) {
 87                 e.cap-=d;
 88                 G[e.to][e.rev].cap+=d;
 89                 return d;
 90             }
 91         }
 92     }
 93     return 0;
 94 }
 95 int maxflow(int s,int t) {
 96     int flow=0;
 97     for(;;) {
 98         bfs(s);
 99         if(level[t]<0)return flow;
100         memset(iter,0,sizeof(iter));
101         int f;
102         while((f = dfs(s,t,INF))>0) {
103             flow +=f;
104         }
105     }
106 }
107 
108 int a[maxn],b[maxn];
109 int prime[maxn];//存这是第几个素数
110 vector<int> v;//存素数
111 void sieve(int _n) {
112     int tot=0;
113     memset(prime,0,sizeof(prime));
114     prime[0]=-1;
115     prime[1]=-1;
116     for(int i=2; i<=_n; i++) {
117         if (prime[i]==0) {
118             prime[i]=tot++;
119             v.push_back(i);
120             for(int j=i*2; j<=_n; j+=i) {
121                 prime[j]=-1;
122             }
123         }
124     }
125 }
126 
127 vector<int> k[maxn/10];//大概估计一下区间内素数个数不足总数1/10
128 
129 void df(int x,int pos) {//x为本身的数,pos为标号
130     if(x==1)return;//1与任何数gcd都是1所以直接不考虑
131     for(int i=0; i<v.size(); i++) {
132         if(x<v[i]) {//任何数的质因数肯定小于等于本身,大于就return了
133             return ;
134         }
135         if(prime[x]!=-1) {//为素数
136             k[prime[x]].push_back(pos);
137             return ;
138         }
139         if(x%v[i]==0)k[i].push_back(pos);//如果是合数就判断当前枚举素数是不是该合数的质因数
140         while(x%v[i]==0) {//去掉重复质因数
141             x/=v[i];
142         }
143     }
144 }
145 void df2(int x,int pos) {
146     if(x==1)return;
147     for(int i=0; i<v.size(); i++) {
148         if(x<v[i]) {
149             return ;
150         }
151         if(prime[x]!=-1) {
152             i=prime[x];
153             for(int j=0; j<k[i].size(); j++) {//与有相同质因数的女生全部连边
154                 add(k[i][j],pos,1);
155             }
156             return ;
157         }
158         if(x%v[i]==0) {
159             for(int j=0; j<k[i].size(); j++) {//同上
160                 add(k[i][j],pos,1);
161             }
162         }
163         while(x%v[i]==0) {
164             x/=v[i];
165         }
166     }
167 }
168 
169 int main() {
170     sieve(1e6+1);//预处理素数筛
171     int t,n;
172     scanf("%d",&t);
173     while(t--) {
174         scanf("%d",&n);
175         for(int i=0; i<v.size(); i++) {
176             k[i].clear();
177         }
178         for(int i=1; i<=n; i++) {
179             scanf("%d",&a[i]);
180         }
181         for(int i=1; i<=n; i++) {
182             char s[2];
183             scanf("%s",s);
184             if(s[0]=='F') {
185                 b[i]=1;//女1男0
186             } else b[i]=0;
187         }
188         init(n+1);
189         for(int i=1; i<=n; i++) {
190             if(b[i]==1) {
191                 df(a[i],i);
192             }
193         }
194         for(int i=1; i<=n; i++) {
195             if(b[i]==0) {
196                 df2(a[i],i);
197             }
198         }
199         for(int i=1; i<=n; i++) {
200 
201             if(b[i]==1) {
202                 add(0,i,1);
203             } else add(i,n+1,1);
204         }
205         printf("%d\n",n-maxflow(0,n+1));
206     }
207     return 0;
208 }
View Code

 

posted @ 2018-08-16 00:44  llllrj  阅读(321)  评论(0编辑  收藏  举报