AC通道:http://codeforces.com/problemset/problem/498/C
【题目大意】
给你一个二分图,左边点的编号为奇数,右边为偶数,给出每个点的权值,每次操作可将图中有边相连的两个点的权值除以他们的一个公因数(不能是1),问最多可以执行多少次这样的操作。
【题解】
为了得到了最多的操作次数,每次操作一定是除以两个数的公共的质因数。
所以我们对于每一个质因数建图,原图中的边的两个点都存在这个这个质因数的连边,边权为两个点这个质因数的数量中较小的那一个,奇数点与源建边,边权为它存在这个质因
数的个数,偶数点同理,与汇建边,然后跑最大流。
因为通过筛素数,我们也就能筛出105以内的素数,对于大于这个边界的我们可以考虑,一个数(109以内)最多只能存在一个105以上的质因数,这个很容易想到,那么也就是最后
我们对所有大于105的质因数建一张图,对于原图中的边,只有两个点相等才建边,边权为1,(原数小于105的质因数已经全部约去)
——转自lin_黎晨
【出错记录】
1、while(a[j]%prime[i]==0) num[j]++,a[j]/=prime[i]; 手残把while写成了if
2、没有考虑到每个点的流量也有限制,直接按照边建图。
3、忘记将num数组清零
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
#define FILE "read"
#define MAXN 110000
#define INF 1000000000
#define up(i,j,n) for(int i=j;i<=n;++i)
#define dn(i,j,n) for(int i=j;i>=n;--i)
#define cmax(a,b) a=max(a,b)
#define cmin(a,b) a=min(a,b)
struct node{int y,next,v,rel;}e[MAXN*2];
int n,m,cnt,ans,len,S,T,a[MAXN],num[MAXN],X[MAXN],Y[MAXN],prime[50010],check[50010],Link[MAXN],level[MAXN],q[MAXN];
namespace INIT{
char buf[1<<15],*fs,*ft;
inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline int read(){
int x=0,f=1; char ch=getc();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getc();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getc();}
return x*f;
}
}using namespace INIT;
void insert(int x,int y,int v){
e[++len].next=Link[x];Link[x]=len;e[len].y=y;e[len].v=v;e[len].rel=len+1;
e[++len].next=Link[y];Link[y]=len;e[len].y=x;e[len].v=0;e[len].rel=len-1;
}
void pre(){
up(i,2,50000){
if(!check[i]) prime[++cnt]=i;
for(int j=1;i*prime[j]<=50000&&j<=cnt;j++){
check[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
}
bool bfs(){
memset(level,-1,sizeof(level));
int head=0,tail=1;q[1]=S;level[S]=0;
while(++head<=tail)
for(int i=Link[q[head]];i;i=e[i].next)
if(level[e[i].y]==-1&&e[i].v){
q[++tail]=e[i].y;
level[q[tail]]=level[q[head]]+1;
}
return level[T]>=0;
}
int MAXFLOW(int x,int flow){
if(x==T) return flow;
int maxflow(0),d(0);
for(int i=Link[x];i&&maxflow<flow;i=e[i].next)
if(level[e[i].y]==level[x]+1&&e[i].v)
if(d=MAXFLOW(e[i].y,min(e[i].v,flow-maxflow))){
maxflow+=d; e[i].v-=d; e[e[i].rel].v+=d;
}
if(!maxflow) level[x]=-1;
return maxflow;
}
void solve(){int d(0);while(bfs())while(d=MAXFLOW(S,INF))ans+=d;}
void clear(){len=0;memset(Link,0,sizeof(Link));memset(num,0,sizeof(num));}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
n=read(); m=read(); S=0; T=n+1; pre();
up(i,1,n) a[i]=read();
up(i,1,m){
X[i]=read(); Y[i]=read();
if(Y[i]&1) swap(X[i],Y[i]);
}
up(i,1,cnt){
clear();
up(j,1,n)while(a[j]%prime[i]==0) num[j]++,a[j]/=prime[i];
up(j,1,n){
if(j&1) insert(S,j,num[j]);
else insert(j,T,num[j]);
}
up(j,1,m)insert(X[j],Y[j],min(num[X[j]],num[Y[j]]));
solve();
}
clear();
up(i,1,n){
if(i&1) insert(S,i,1);
else insert(i,T,1);
}
up(i,1,m)if(a[X[i]]!=1&&a[X[i]]==a[Y[i]])insert(X[i],Y[i],1);
solve();
printf("%d\n",ans);
return 0;
}