直接讲做法,
依次去计算每个素数在整个序列中最多能被约多少次,然后每个素数的约数和就是答案。
计算每个素数约数次数用网络流来做。
假设我们现在计算素数2。
先建立图,图的构成是这样,
编号为奇数的点在左边放一排,编号为偶数的点在右边放一排,
然后对于每个奇数编号点,假设他能约2的次数为k,那么连一条从S(源点)到它的边,流量为k。
对于每个偶数编号的点,假设他能约2的次数为kk,连一条从它到T(汇点)的边,流量为k。
最后对于每个题目中的每个pair,则表示一条从奇数点到偶数点的边,流量为inf。
然后跑出的最大流就是这个素数能取得的最大约数。
下面是代码(网络流部分是网上随意找的代码)
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <vector>
#include <math.h>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
using namespace std;
#define FOR(i, j, k) for(int i=(j);i<=(k);i++)
#define REP(i, n) for(int i=0;i<(n);i++)
#define mst(x, y) memset(x, y, sizeof(x));
#define pii pair<int, int>
#define fr first
#define sc second
#define left myleft
#define right myright
#define ll long long
#define ull unsigned long long
#define seed 1331
#define mod ((int)1e9+7)
#define eps 1e-5
#define pdd pair<double, double>
vector <int> ps;
bool vis[300009];
void init(){
mst(vis, 0);
for(int i=2;i<=2e5;i++) if(!vis[i])
for(int j=i+i;j<=2e5;j+=i) vis[j] = 1;
for(int i=2;i*i<=1e9;i++) if(!vis[i])
ps.push_back(i);
}
int a[102], n, m, ans = 0;
pii pa[102];
const int Ni = 210;
const int MAX = 1<<26;
struct Edge{
int u,v,c;
int next;
}edge[20*Ni];
int edn;//边数
int p[Ni];//父亲
int d[Ni];
int sp,tp;//原点,汇点
void addedge(int u,int v,int c)
{
edge[edn].u=u; edge[edn].v=v; edge[edn].c=c;
edge[edn].next=p[u]; p[u]=edn++;
edge[edn].u=v; edge[edn].v=u; edge[edn].c=0;
edge[edn].next=p[v]; p[v]=edn++;
}
int bfs()
{
queue <int> q;
memset(d,-1,sizeof(d));
d[sp]=0;
q.push(sp);
while(!q.empty())
{
int cur=q.front();
q.pop();
for(int i=p[cur];i!=-1;i=edge[i].next)
{
int u=edge[i].v;
if(d[u]==-1 && edge[i].c>0)
{
d[u]=d[cur]+1;
q.push(u);
}
}
}
return d[tp] != -1;
}
int dfs(int a,int b)
{
int r=0;
if(a==tp)return b;
for(int i=p[a];i!=-1 && r<b;i=edge[i].next)
{
int u=edge[i].v;
if(edge[i].c>0 && d[u]==d[a]+1)
{
int x=min(edge[i].c,b-r);
x=dfs(u,x);
r+=x;
edge[i].c-=x;
edge[i^1].c+=x;
}
}
if(!r)d[a]=-2;
return r;
}
int dinic(int sp,int tp)
{
int total=0,t;
while(bfs())
{
while(t=dfs(sp,MAX))
total+=t;
}
return total;
}
void cal(int v){
FOR(j, 1, n){
int cnt = 0, x = a[j];
while(x % v == 0) cnt ++, x /= v;
if(j&1) addedge(sp, j, cnt);
else addedge(j, tp, cnt);
}
REP(j, m) if(a[pa[j].fr]%v == 0 && a[pa[j].sc]%v == 0){
if(pa[j].fr & 1) addedge(pa[j].fr, pa[j].sc, 1000000);
else addedge(pa[j].sc, pa[j].fr, 1000000);
}
int tmp = dinic(sp, tp);
ans += tmp;
FOR(i, 1, n) while(a[i] % v == 0)
a[i] /= v;
}
int main(){
// freopen("in", "r", stdin);
init();
cin>>n;
cin>>m;
FOR(i,1, n) cin>>a[i];
REP(i, m) cin>>pa[i].fr>>pa[i].sc;
REP(i, ps.size()){
edn = 0;
sp = 0;
tp = n+1;
mst(p, -1);
mst(edge, -1);
int v = ps[i];
cal(v);
}
FOR(i, 1, n){
int v = a[i];
if(v == 1) continue;
edn = 0;
sp = 0;
tp = n+1;
mst(p, -1);
mst(edge, -1);
cal(v);
}
cout<<ans<<endl;
}