#include <bits/stdc++.h>
using namespace std;

const int N = 1e2 + 100;

class MaxFlow {
  typedef int F;
  const F INF = 1e9 + 23;

  struct edge {
    int to; F cap, flow;
    edge() {}
    edge(int to, F c, F f)
      : to(to), cap(c), flow(f) {}
  };

  int V;
  vector<edge> es;
  vector<int> gr[N];
  int ptr[N], lv[N], q[N];

  bool bfs(int s, int d) {
    fill(lv, lv + V, -1);
    int qh = 0, qt = 0;
    lv[s] = 0; q[qt++] = s;
    while (qh < qt) {
      int v = q[qh++];
      for (auto eid : gr[v]) {
        edge e = es[eid];
        if (lv[e.to] == -1 and e.flow < e.cap) {
          lv[e.to] = lv[v] + 1; q[qt++] = e.to;
        }
      }
    }
    return lv[d] != -1;
  }

  F dfs(int v, int d, F val) {
    if (v == d) return val;

    for ( ; ptr[v] < (int)gr[v].size(); ++ptr[v]) {
      int eid = gr[v][ptr[v]];
      edge e = es[eid];
      if (lv[e.to] != lv[v] + 1) continue;
      int left = e.cap - e.flow;
      if (left == 0) continue;
      F pushed = dfs(e.to, d, min(val, e.cap - e.flow));
      if (pushed > 0) {
        es[eid].flow += pushed;
        es[eid^1].flow -= pushed;
        return pushed;
      }
    }
    return 0;
  }

public:
  MaxFlow(int v) {
    Reset(v);
  }

  void Reset(int v) {
    V = v;
    es.clear();
    for (int i = 0; i < V; ++i) gr[i].clear();
  }

  void AddEdge(int fr, int to, F cap) {
    es.emplace_back(to, cap, 0);
    gr[fr].push_back((int)es.size()-1);
    es.emplace_back(fr, 0, 0);
    gr[to].push_back((int)es.size()-1);
  }

  F Compute(int s, int d) {
    F ans = 0;
    while (bfs(s, d)) {
      fill(ptr, ptr + V, 0);
      while (F now = dfs(s, d, INF)) ans += now;
    }
    return ans;
  }
};

int a[N];//, cnt[N];
int x[N], y[N];
set<int> divs;

int main()
{
  ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  int n, m;
  cin >> n >> m;
  for (int i = 1; i <= n; ++i) cin >> a[i];
  for (int i = 0; i < m; ++i) {
    cin >> x[i] >> y[i];
    if (x[i] & 1) swap(x[i], y[i]);
  }

  for (int i = 1; i <= n; ++i) {
    int v = a[i];
    for (int p = 2; p <= v/p; ++p) {
      if (v % p == 0) {
        divs.insert(p);
        while (v % p == 0) v /= p;
      }
    }
    if (v > 1) divs.insert(v);
  }

  MaxFlow mf(n+2);
  int ans = 0;
  for (auto d : divs) {
    mf.Reset(n+2);
    for (int i = 1; i <= n; ++i) {
      int cnt = 0;
      while (a[i] % d == 0) {
        ++cnt;
        a[i] /= d;
      }
      if (i & 1) mf.AddEdge(i, n+1, cnt);
      else mf.AddEdge(0, i, cnt);
    }
    for (int i = 0; i < m; ++i) {
      //int cap = min(cnt[x[i]], cnt[y[i]]);
      mf.AddEdge(x[i], y[i], 100);
    }
    ans += mf.Compute(0, n+1);
  }
  cout << ans << '\n';
}
// g++ -W -Wall -Wextra -pedantic -std=c++0x -o p main.cpp


#include <bits/stdc++.h>
using namespace std;

const int N = 1e2 + 100;

class MaxFlow {
  typedef int F;
  const F INF = 1e9 + 23;

  struct edge {
    int to; F cap, flow;
    edge() {}
    edge(int to, F c, F f)
      : to(to), cap(c), flow(f) {}
  };

  vector<edge> es;
  vector<int> gr[N];
  int ptr[N], lv[N], q[N];

  bool bfs(int s, int d) {
    fill(lv, lv + N, -1);
    int qh = 0, qt = 0;
    lv[s] = 0; q[qt++] = s;
    while (qh < qt) {
      int v = q[qh++];
      for (auto eid : gr[v]) {
        edge e = es[eid];
        if (lv[e.to] == -1 and e.flow < e.cap) {
          lv[e.to] = lv[v] + 1; q[qt++] = e.to;
        }
      }
    }
    return lv[d] != -1;
  }

  F dfs(int v, int d, F val) {
    if (v == d) return val;

    for ( ; ptr[v] < (int)gr[v].size(); ++ptr[v]) {
      int eid = gr[v][ptr[v]];
      edge e = es[eid];
      if (lv[e.to] != lv[v] + 1) continue;
      F pushed = dfs(e.to, d, min(val, e.cap - e.flow));
      if (pushed > 0) {
        es[eid].flow += pushed;
        es[eid^1].flow -= pushed;
        return pushed;
      }
    }
    return 0;
  }

public:
  MaxFlow() {
    Reset();
  }

  void Reset() {
    es.clear();
    for (int i = 0; i < N; ++i) gr[i].clear();
  }

  void AddEdge(int fr, int to, F cap) {
    es.emplace_back(to, cap, 0);
    gr[fr].push_back((int)es.size()-1);
    es.emplace_back(fr, 0, 0);
    gr[to].push_back((int)es.size()-1);
  }

  F Compute(int s, int d) {
    F ans = 0;
    while (bfs(s, d)) {
      fill(ptr, ptr + N, 0);
      while (F now = dfs(s, d, INF)) ans += now;
    }
    return ans;
  }
};

int a[N], cnt[N];
int x[N], y[N];
set<int> divs;

int main()
{
  ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  int n, m;
  cin >> n >> m;
  for (int i = 1; i <= n; ++i) cin >> a[i];
  for (int i = 0; i < m; ++i) {
    cin >> x[i] >> y[i];
    if (x[i] & 1) swap(x[i], y[i]);
  }

  for (int i = 1; i <= n; ++i) {
    int v = a[i];
    for (int p = 2; p <= v/p; ++p) {
      if (v % p == 0) {
        divs.insert(p);
        while (v % p == 0) v /= p;
      }
    }
    if (v > 1) divs.insert(v);
  }

  MaxFlow mf;
  int ans = 0;
  for (auto d : divs) {
    mf.Reset();
    for (int i = 1; i <= n; ++i) {
      cnt[i] = 0;
      while (a[i] % d == 0) {
        ++cnt[i];
        a[i] /= d;
      }
      if (i & 1) mf.AddEdge(i, n+1, cnt[i]);
      else mf.AddEdge(0, i, cnt[i]);
    }
    for (int i = 0; i < m; ++i) {
      int cap = min(cnt[x[i]], cnt[y[i]]);
      mf.AddEdge(x[i], y[i], cap);
    }
    ans += mf.Compute(0, n+1);
  }
  cout << ans << '\n';
}
// g++ -W -Wall -Wextra -pedantic -std=c++0x -o p main.cpp


#include <bits/stdc++.h>
using namespace std;

const int N = 1e2 + 100;

class MaxFlow {
  typedef int F;
  const F INF = 1e9 + 23;

  struct edge {
    int to; F cap, flow;
    edge() {}
    edge(int to, F c, F f)
      : to(to), cap(c), flow(f) {}
  };

  vector<edge> es;
  vector<int> gr[N];
  int ptr[N], lv[N], q[N];

  bool bfs(int s, int d) {
    fill(lv, lv + N, -1);
    int qh = 0, qt = 0;
    lv[s] = 0; q[qt++] = s;
    while (qh < qt) {
      int v = q[qh++];
      for (auto eid : gr[v]) {
        edge e = es[eid];
        if (lv[e.to] == -1 and e.flow < e.cap) {
          lv[e.to] = lv[v] + 1; q[qt++] = e.to;
        }
      }
    }
    return lv[d] != -1;
  }

  F dfs(int v, int d, F val) {
    if (v == d) return val;

    for ( ; ptr[v] < (int)gr[v].size(); ++ptr[v]) {
      int eid = gr[v][ptr[v]];
      edge e = es[eid];
      if (lv[e.to] != lv[v] + 1) continue;
      F pushed = dfs(e.to, d, min(val, e.cap - e.flow));
      if (pushed > 0) {
        es[eid].flow += pushed;
        es[eid^1].flow -= pushed;
        return pushed;
      }
    }
    return 0;
  }

public:
  MaxFlow() {
    Reset();
  }

  void Reset() {
    es.clear();
    for (int i = 0; i < N; ++i) gr[i].clear();
  }

  void AddEdge(int fr, int to, F cap) {
    es.emplace_back(to, cap, 0);
    gr[fr].push_back((int)es.size()-1);
    es.emplace_back(fr, 0, 0);
    gr[to].push_back((int)es.size()-1);
  }

  F Compute(int s, int d) {
    F ans = 0;
    while (bfs(s, d)) {
      fill(ptr, ptr + N, 0);
      while (F now = dfs(s, d, INF)) ans += now;
    }
    return ans;
  }
};

int a[N];//, cnt[N];
int x[N], y[N];
set<int> divs;

int main()
{
  ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  int n, m;
  cin >> n >> m;
  for (int i = 1; i <= n; ++i) cin >> a[i];
  for (int i = 0; i < m; ++i) {
    cin >> x[i] >> y[i];
    if (x[i] & 1) swap(x[i], y[i]);
  }

  for (int i = 1; i <= n; ++i) {
    int v = a[i];
    for (int p = 2; p <= v/p; ++p) {
      if (v % p == 0) {
        divs.insert(p);
        while (v % p == 0) v /= p;
      }
    }
    if (v > 1) divs.insert(v);
  }

  MaxFlow mf;
  int ans = 0;
  for (auto d : divs) {
    mf.Reset();
    for (int i = 1; i <= n; ++i) {
      int cnt = 0;
      while (a[i] % d == 0) {
        ++cnt;
        a[i] /= d;
      }
      if (i & 1) mf.AddEdge(i, n+1, cnt);
      else mf.AddEdge(0, i, cnt);
    }
    for (int i = 0; i < m; ++i) {
      //int cap = min(cnt[x[i]], cnt[y[i]]);
      mf.AddEdge(x[i], y[i], 100);
    }
    ans += mf.Compute(0, n+1);
  }
  cout << ans << '\n';
}
// g++ -W -Wall -Wextra -pedantic -std=c++0x -o p main.cpp


#include <bits/stdc++.h>
using namespace std;

const int N = 1e2 + 100;

class MaxFlow {
  typedef int F;
  const F INF = 1e9 + 23;

  struct edge {
    int to; F cap, flow;
    edge() {}
    edge(int to, F c, F f)
      : to(to), cap(c), flow(f) {}
  };

  int V;
  vector<edge> es;
  vector<int> gr[N];
  int ptr[N], lv[N], q[N];

  bool bfs(int s, int d) {
    fill(lv, lv + V, -1);
    int qh = 0, qt = 0;
    lv[s] = 0; q[qt++] = s;
    while (qh < qt) {
      int v = q[qh++];
      for (auto eid : gr[v]) {
        edge e = es[eid];
        if (lv[e.to] == -1 and e.flow < e.cap) {
          lv[e.to] = lv[v] + 1; q[qt++] = e.to;
        }
      }
    }
    return lv[d] != -1;
  }

  F dfs(int v, int d, F val) {
    if (v == d) return val;

    for ( ; ptr[v] < (int)gr[v].size(); ++ptr[v]) {
      int eid = gr[v][ptr[v]];
      edge e = es[eid];
      if (lv[e.to] != lv[v] + 1) continue;
      F pushed = dfs(e.to, d, min(val, e.cap - e.flow));
      if (pushed > 0) {
        es[eid].flow += pushed;
        es[eid^1].flow -= pushed;
        return pushed;
      }
    }
    return 0;
  }

public:
  MaxFlow(int v) {
    Reset(v);
  }

  void Reset(int v) {
    V = v;
    es.clear();
    for (int i = 0; i < V; ++i) gr[i].clear();
  }

  void AddEdge(int fr, int to, F cap) {
    es.emplace_back(to, cap, 0);
    gr[fr].push_back((int)es.size()-1);
    es.emplace_back(fr, 0, 0);
    gr[to].push_back((int)es.size()-1);
  }

  F Compute(int s, int d) {
    F ans = 0;
    while (bfs(s, d)) {
      fill(ptr, ptr + V, 0);
      while (F now = dfs(s, d, INF)) ans += now;
    }
    return ans;
  }
};

int a[N];//, cnt[N];
int x[N], y[N];
set<int> divs;

int main()
{
  ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  int n, m;
  scanf("%d %d", &n, &m);
  //cin >> n >> m;
  for (int i = 1; i <= n; ++i) {
    scanf("%d", &a[i]);
    //cin >> a[i];
  }
  for (int i = 0; i < m; ++i) {
    scanf("%d %d", &x[i], &y[i]);
    //cin >> x[i] >> y[i];
    if (x[i] & 1) swap(x[i], y[i]);
  }

  for (int i = 1; i <= n; ++i) {
    int v = a[i];
    for (int p = 2; p <= v/p; ++p) {
      if (v % p == 0) {
        divs.insert(p);
        while (v % p == 0) v /= p;
      }
    }
    if (v > 1) divs.insert(v);
  }

  MaxFlow mf(n+2);
  int ans = 0;
  for (auto d : divs) {
    mf.Reset(n+2);
    for (int i = 1; i <= n; ++i) {
      int cnt = 0;
      while (a[i] % d == 0) {
        ++cnt;
        a[i] /= d;
      }
      if (i & 1) mf.AddEdge(i, n+1, cnt);
      else mf.AddEdge(0, i, cnt);
    }
    for (int i = 0; i < m; ++i) {
      //int cap = min(cnt[x[i]], cnt[y[i]]);
      mf.AddEdge(x[i], y[i], 100);
    }
    ans += mf.Compute(0, n+1);
  }
  printf("%d\n", ans);
  //cout << ans << '\n';
}
// g++ -W -Wall -Wextra -pedantic -std=c++0x -o p main.cpp


#include <bits/stdc++.h>
using namespace std;

const int N = 1e2 + 100;

class MaxFlow {
  typedef int F;
  const F INF = 1e9 + 23;

  struct edge {
    int to; F cap, flow;
    edge() {}
    edge(int to, F c, F f)
      : to(to), cap(c), flow(f) {}
  };

  int V;
  vector<edge> es;
  vector<int> gr[N];
  int ptr[N], lv[N], q[N];

  bool bfs(int s, int d) {
    fill(lv, lv + V, -1);
    int qh = 0, qt = 0;
    lv[s] = 0; q[qt++] = s;
    while (qh < qt) {
      int v = q[qh++];
      for (auto eid : gr[v]) {
        edge e = es[eid];
        if (lv[e.to] == -1 and e.flow < e.cap) {
          lv[e.to] = lv[v] + 1; q[qt++] = e.to;
        }
      }
    }
    return lv[d] != -1;
  }

  F dfs(int v, int d, F val) {
    if (v == d) return val;

    for ( ; ptr[v] < (int)gr[v].size(); ++ptr[v]) {
      int eid = gr[v][ptr[v]];
      edge e = es[eid];
      if (lv[e.to] != lv[v] + 1) continue;
      int left = e.cap - e.flow;
      if (left == 0) continue;
      F pushed = dfs(e.to, d, min(val, e.cap - e.flow));
      if (pushed > 0) {
        es[eid].flow += pushed;
        es[eid^1].flow -= pushed;
        return pushed;
      }
    }
    return 0;
  }

public:
  MaxFlow(int v) {
    Reset(v);
  }

  void Reset(int v) {
    V = v;
    es.clear();
    for (int i = 0; i < V; ++i) gr[i].clear();
  }

  void AddEdge(int fr, int to, F cap) {
    es.emplace_back(to, cap, 0);
    gr[fr].push_back((int)es.size()-1);
    es.emplace_back(fr, 0, 0);
    gr[to].push_back((int)es.size()-1);
  }

  F Compute(int s, int d) {
    F ans = 0;
    while (bfs(s, d)) {
      fill(ptr, ptr + V, 0);
      while (F now = dfs(s, d, INF)) ans += now;
    }
    return ans;
  }
};

int a[N];//, cnt[N];
int x[N], y[N];
set<int> divs;

int main()
{
  ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  int n, m;
  scanf("%d %d", &n, &m);
  //cin >> n >> m;
  for (int i = 1; i <= n; ++i) {
    scanf("%d", &a[i]);
    //cin >> a[i];
  }
  for (int i = 0; i < m; ++i) {
    scanf("%d %d", &x[i], &y[i]);
    //cin >> x[i] >> y[i];
    if (x[i] & 1) swap(x[i], y[i]);
  }

  for (int i = 1; i <= n; ++i) {
    int v = a[i];
    for (int p = 2; p <= v/p; ++p) {
      if (v % p == 0) {
        divs.insert(p);
        while (v % p == 0) v /= p;
      }
    }
    if (v > 1) divs.insert(v);
  }

  MaxFlow mf(n+2);
  int ans = 0;
  for (auto d : divs) {
    mf.Reset(n+2);
    for (int i = 1; i <= n; ++i) {
      int cnt = 0;
      while (a[i] % d == 0) {
        ++cnt;
        a[i] /= d;
      }
      if (i & 1) mf.AddEdge(i, n+1, cnt);
      else mf.AddEdge(0, i, cnt);
    }
    for (int i = 0; i < m; ++i) {
      //int cap = min(cnt[x[i]], cnt[y[i]]);
      mf.AddEdge(x[i], y[i], 100);
    }
    ans += mf.Compute(0, n+1);
  }
  printf("%d\n", ans);
  //cout << ans << '\n';
}
// g++ -W -Wall -Wextra -pedantic -std=c++0x -o p main.cpp


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <stack>
#include <list>
#include <queue>
#include <deque>
#include <cctype>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include <numeric>
#include <cmath>
using namespace std;

pair < int ,int > pary[105];
int pocz=0,kon=200;
const int INF = 1000000001;
const int N=200;
bool t[40000];
int liczby[105],x,y;
vector<int> krawedzie[N];
vector<int>::iterator poczatek[N];
int przepustowosc[N][N], odleglosc[N], q[N];

void AddEdge(int a,int b,int c){
  przepustowosc[a][b]=c;
}

int bfs(int s,int t,int n){
  for (int i=0; i<n; ++i) odleglosc[i]=-1;
  odleglosc[s]=0;
  int beg=0,end=0;
  q[end++]=s;
  while (beg<end){
    int v=q[beg++];
   for (vector<int>::iterator it=krawedzie[v].begin(); it!=krawedzie[v].end(); ++it)
    {
      if (przepustowosc[v][*it]>0 && odleglosc[*it]==-1){
        odleglosc[*it]=odleglosc[v]+1;

        q[end++]=*it;
      }
    }
  }
  return odleglosc[t]!=-1;
}
int r=0;
int dfs(int x,int t,int minimum){
  int res=0;
  if (x==t || minimum==0) return minimum;
  //UWAGA: it jest referencja!!!
  for(vector<int>::iterator &it=poczatek[x];it!=krawedzie[x].end(); ++it){
    if (odleglosc[x]+1==odleglosc[*it] && przepustowosc[x][*it]>0){
      int y=dfs(*it,t,min(minimum,przepustowosc[x][*it]));
      //odwracamy czesc przepustowosci
      przepustowosc[x][*it]-=y;
      przepustowosc[*it][x]+=y;
      minimum-=y; res+=y;
      if (minimum==0) break;
    }
  }
  return res;
}
int n,m;
vector < int > primes;
int Maxflow(int s,int t,int n){
  int res=0;
  while (bfs(s,t,n)){
    for (int i=0; i<n; ++i) poczatek[i]=krawedzie[i].begin();
    res+=dfs(s,t,INF);
  }
  return res;
}

int main(){
cin>>n>>m;
kon=n+1;
for(int i=0;n>i;i++)
{
    cin>>liczby[i+1];
    int l=liczby[i+1];
    for(int j=2;j*j<=l;j++)
    {
        while(l%j==0)
        {
            primes.push_back(j);
                l/=j;
        }
    }
    if(l!=1)
        primes.push_back(l);
}
for(int i=0;m>i;i++)
{
    cin>>x>>y;
    pary[i].first=x;
    pary[i].second=y;
    if(x%2==0)
        swap(pary[i].first,pary[i].second);
    krawedzie[pary[i].first].push_back(pary[i].second);
    krawedzie[pary[i].second].push_back(pary[i].first);
}
sort(primes.begin(),primes.end());
for(int i=1;n>=i;i+=2)
    krawedzie[0].push_back(i);
for(int i=2;n>=i;i+=2)
    krawedzie[i].push_back(n+1);
for(int i=0;primes.size()>i;i++)
{
if(i!=0 and primes[i]==primes[i-1] )
    continue;
    for(int g=0;n+1>=g;g++)
    {
        for(int f=0;n+1>=f;f++)
            przepustowosc[g][f]=0;
    }
    for(int j=0;m>j;j++)
    {
            AddEdge(pary[j].first,pary[j].second,1000);
    }
    for(int j=1;n>=j;j++)
    {
        int xd=liczby[j];
        int ile=0;
        while(xd%primes[i]==0)
        {
            ile++;
            xd/=primes[i];
        }
        if(j%2==1)
            AddEdge(pocz,j,ile);
        else
            AddEdge(j,kon,ile);
    }
    r+=Maxflow(pocz,kon,n+2);
}
cout<<r;

  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <stack>
#include <list>
#include <queue>
#include <deque>
#include <cctype>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include <numeric>
#include <cmath>
using namespace std;

pair < int ,int > pary[105];
int pocz=0,kon=200;
const int INF = 1000000001;
const int N=200;
bool t[40000];
int liczby[105],x,y;
vector<int> krawedzie[N];
vector<int>::iterator poczatek[N];
int przepustowosc[N][N], odleglosc[N], q[N];

void AddEdge(int a,int b,int c){
  przepustowosc[a][b]=c;
}

int bfs(int s,int t,int n){
  for (int i=0; i<n; ++i) odleglosc[i]=-1;
  odleglosc[s]=0;
  int beg=0,end=0;
  q[end++]=s;
  while (beg<end){
    int v=q[beg++];
   for (vector<int>::iterator it=krawedzie[v].begin(); it!=krawedzie[v].end(); ++it)
    {
      if (przepustowosc[v][*it]>0 && odleglosc[*it]==-1){
        odleglosc[*it]=odleglosc[v]+1;

        q[end++]=*it;
      }
    }
  }
  return odleglosc[t]!=-1;
}
int r=0;
int dfs(int x,int t,int minimum){
  int res=0;
  if (x==t || minimum==0) return minimum;
  //UWAGA: it jest referencja!!!
  for(vector<int>::iterator &it=poczatek[x];it!=krawedzie[x].end(); ++it){
    if (odleglosc[x]+1==odleglosc[*it] && przepustowosc[x][*it]>0){
      int y=dfs(*it,t,min(minimum,przepustowosc[x][*it]));
      //odwracamy czesc przepustowosci
      przepustowosc[x][*it]-=y;
      przepustowosc[*it][x]+=y;
      minimum-=y; res+=y;
      if (minimum==0) break;
    }
  }
  return res;
}
int n,m;
vector < int > primes;
int Maxflow(int s,int t,int n){
  int res=0;
  while (bfs(s,t,n)){
    for (int i=0; i<n; ++i) poczatek[i]=krawedzie[i].begin();
    res+=dfs(s,t,INF);
  }
  return res;
}

int main(){
cin>>n>>m;
kon=n+1;
for(int i=0;n>i;i++)
{
    cin>>liczby[i+1];
    int l=liczby[i+1];
    for(int i=2;i*i<=l;i++)
    {
        if(l%i==0)
        {
            primes.push_back(i);
            while(l%i==0)
                l/=i;
        }
    }
    if(l!=1)
        primes.push_back(l);
}
for(int i=0;m>i;i++)
{
    cin>>x>>y;
    pary[i].first=x;
    pary[i].second=y;
    if(x%2==0)
        swap(pary[i].first,pary[i].second);
    krawedzie[pary[i].first].push_back(pary[i].second);
    krawedzie[pary[i].second].push_back(pary[i].first);
}
sort(primes.begin(),primes.end());
for(int i=1;n>=i;i+=2)
    krawedzie[0].push_back(i);
for(int i=2;n>=i;i+=2)
    krawedzie[i].push_back(n+1);
for(int i=0;primes.size()>i;i++)
{
if(i!=0 and primes[i]==primes[i-1] and t[i-1]==1)
    continue;
t[i]=1;

    for(int g=1;n>=g;g++)
    {
        for(int f=1;n>=f;f++)
            przepustowosc[g][f]=0;
    }
    for(int j=0;m>j;j++)
    {
        if(liczby[pary[j].first]%primes[i]==0 and liczby[pary[j].second]%primes[i]==0)
        {
            AddEdge(pary[j].first,pary[j].second,1);
        }

        AddEdge(pocz,pary[j].first,1);
        AddEdge(pary[j].second,kon,1);
    }
    r+=Maxflow(pocz,kon,n+2);
}
cout<<r;

  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <stack>
#include <list>
#include <queue>
#include <deque>
#include <cctype>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include <numeric>
#include <cmath>
using namespace std;

pair < int ,int > pary[105];
int pocz=0,kon=200;
const int INF = 1000000001;
const int N=200;
bool t[40000];
int liczby[105],x,y;
vector<int> krawedzie[N];
vector<int>::iterator poczatek[N];
int przepustowosc[N][N], odleglosc[N], q[N];

void AddEdge(int a,int b,int c){
  przepustowosc[a][b]=c;
}

int bfs(int s,int t,int n){
  for (int i=0; i<n; ++i) odleglosc[i]=-1;
  odleglosc[s]=0;
  int beg=0,end=0;
  q[end++]=s;
  while (beg<end){
    int v=q[beg++];
   for (vector<int>::iterator it=krawedzie[v].begin(); it!=krawedzie[v].end(); ++it)
    {
      if (przepustowosc[v][*it]>0 && odleglosc[*it]==-1){
        odleglosc[*it]=odleglosc[v]+1;

        q[end++]=*it;
      }
    }
  }
  return odleglosc[t]!=-1;
}
int r=0;
int dfs(int x,int t,int minimum){
  int res=0;
  if (x==t || minimum==0) return minimum;
  //UWAGA: it jest referencja!!!
  for(vector<int>::iterator &it=poczatek[x];it!=krawedzie[x].end(); ++it){
    if (odleglosc[x]+1==odleglosc[*it] && przepustowosc[x][*it]>0){
      int y=dfs(*it,t,min(minimum,przepustowosc[x][*it]));
      //odwracamy czesc przepustowosci
      przepustowosc[x][*it]-=y;
      przepustowosc[*it][x]+=y;
      minimum-=y; res+=y;
      if (minimum==0) break;
    }
  }
  return res;
}
int n,m;
vector < int > primes;
int Maxflow(int s,int t,int n){
  int res=0;
  while (bfs(s,t,n)){
    for (int i=0; i<n; ++i) poczatek[i]=krawedzie[i].begin();
    res+=dfs(s,t,INF);
  }
  return res;
}

int main(){
cin>>n>>m;
kon=n+1;
for(int i=0;n>i;i++)
{
    cin>>liczby[i+1];
    int l=liczby[i+1];
    for(int j=2;j*j<=l;j++)
    {
        while(l%j==0)
        {
            primes.push_back(j);
                l/=j;
        }
    }
    if(l!=1)
        primes.push_back(l);
}
for(int i=0;m>i;i++)
{
    cin>>x>>y;
    pary[i].first=x;
    pary[i].second=y;
    if(x%2==0)
        swap(pary[i].first,pary[i].second);
    krawedzie[pary[i].first].push_back(pary[i].second);
    krawedzie[pary[i].second].push_back(pary[i].first);
}
sort(primes.begin(),primes.end());
for(int i=1;n>=i;i+=2)
    krawedzie[0].push_back(i);
for(int i=2;n>=i;i+=2)
    krawedzie[i].push_back(n+1);
for(int i=0;primes.size()>i;i++)
{
if(i!=0 and primes[i]==primes[i-1] )
    continue;
    for(int g=0;n+1>=g;g++)
    {
        for(int f=0;n+1>=f;f++)
            przepustowosc[g][f]=0;
    }
    for(int j=0;m>j;j++)
    {
            AddEdge(pary[j].first,pary[j].second,1000);
    }
    for(int j=1;n>=j;j++)
    {
        int xd=liczby[j];
        int ile=0;
        while(xd%primes[i]==0)
        {
            ile++;
            xd/=primes[i];
        }
        if(j%2==1)
            AddEdge(pocz,j,ile);
        else
            AddEdge(j,kon,ile);
    }
    r+=Maxflow(pocz,kon,n+2);
    cout<<r<<" "<<primes[i]<<endl;
}
cout<<r;

  return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <stack>
#include <list>
#include <queue>
#include <deque>
#include <cctype>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include <numeric>
#include <cmath>
using namespace std;

pair < int ,int > pary[105];
int pocz=0,kon=200;
const int INF = 1000000001;
const int N=200;
bool t[40000];
int liczby[105],x,y;
vector<int> krawedzie[N];
int przepustowosc[N][N], odleglosc[N], q[N];

void AddEdge(int a,int b,int c){
  przepustowosc[a][b]=c;
}

int bfs(int s,int t,int n){
  for (int i=0; i<n; ++i) odleglosc[i]=-1;
  odleglosc[s]=0;
  int beg=0,end=0;
  q[end++]=s;
  while (beg<end){
    int v=q[beg++];
   for (vector<int>::iterator it=krawedzie[v].begin(); it!=krawedzie[v].end(); ++it)
    {
      if (przepustowosc[v][*it]>0 && odleglosc[*it]==-1){
        odleglosc[*it]=odleglosc[v]+1;

        q[end++]=*it;
      }
    }
  }
  return odleglosc[t]!=-1;
}
int r=0;
int dfs(int x,int t,int minimum){
  int res=0;
  if (x==t || minimum==0) return minimum;
  //UWAGA: it jest referencja!!!
  for(int g=0;g!=krawedzie[x].size(); g++){
        int it=krawedzie[x][g];
    if (odleglosc[x]+1==odleglosc[it] && przepustowosc[x][it]>0){
      int y=dfs(it,t,min(minimum,przepustowosc[x][it]));
      //odwracamy czesc przepustowosci
      przepustowosc[x][it]-=y;
      przepustowosc[it][x]+=y;
      minimum-=y; res+=y;
      if (minimum==0) break;
    }
  }
  return res;
}
int n,m;
vector < int > primes;
int Maxflow(int s,int t,int n){
  int res=0;
  while (bfs(s,t,n)){
    res+=dfs(s,t,INF);
  }
  return res;
}

int main(){
cin>>n>>m;
kon=n+1;
for(int i=0;n>i;i++)
{
    cin>>liczby[i+1];
    int l=liczby[i+1];
    for(int j=2;j*j<=l;j++)
    {
        while(l%j==0)
        {
            primes.push_back(j);
                l/=j;
        }
    }
    if(l!=1)
        primes.push_back(l);
}
for(int i=0;m>i;i++)
{
    cin>>x>>y;
    pary[i].first=x;
    pary[i].second=y;
    if(x%2==0)
        swap(pary[i].first,pary[i].second);
    krawedzie[pary[i].first].push_back(pary[i].second);
    krawedzie[pary[i].second].push_back(pary[i].first);
}
sort(primes.begin(),primes.end());
for(int i=1;n>=i;i+=2)
    krawedzie[0].push_back(i);
for(int i=2;n>=i;i+=2)
    krawedzie[i].push_back(n+1);
for(int i=0;primes.size()>i;i++)
{
if(i!=0 and primes[i]==primes[i-1] )
    continue;
    for(int g=0;n+1>=g;g++)
    {
        for(int f=0;n+1>=f;f++)
            przepustowosc[g][f]=0;
    }
    for(int j=0;m>j;j++)
    {
            AddEdge(pary[j].first,pary[j].second,1000);
    }
    for(int j=1;n>=j;j++)
    {
        int xd=liczby[j];
        int ile=0;
        while(xd%primes[i]==0)
        {
            ile++;
            xd/=primes[i];
        }
        if(j%2==1)
            AddEdge(pocz,j,ile);
        else
            AddEdge(j,kon,ile);
    }
    r+=Maxflow(pocz,kon,n+2);
}
cout<<r;

  return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define pii pair<int, int>
#define pll pair<ll, ll>
#define fi first
#define se second
#define pb push_back
#define SET(a, b) memset(a, b, sizeof(a))
#define inf 1000000000
#define llinf 1000000000000000000
#define pi atan(1) * 4
#define eps 1e-6
#define FOR(i, a, b, c) for (int i = (a); i <= (b); i += (c))
#define FORD(i, a, b, c) for (int i = (a); i >= (b); i -= (c))
#define FORl(i, a, b, c) for (ll i = (a); i <= (b); i += (c))
#define FORDl(i, a, b, c) for (ll i = (a); i >= (b); i -= (c))
using namespace std;
int n, m;
bool isPrime[32005];
vector<int> prime;
int num[105];
void sieve (int n) {
	SET(isPrime, 1);
	isPrime[0] = isPrime[1] = 0;
	FOR(i, 2, n, 1) {
		if (!isPrime[i]) continue;
		prime.pb(i);
		FOR(j, i * i, n, i) isPrime[j] = 0;
	}
}
map<int, int> mp;
int it = 0;
vector<pii> flow[3005];
void factorise (int n, int i) {
	for (auto p : prime) {
		if (p * p > n) break;
		int f = 0;
		while (n % p == 0) {
			n /= p; f++;
		}
		if (f) {
			if (mp[p] == 0) mp[p] = ++it;
			flow[mp[p]].pb({i, f});
		}
	}
	if (n != 1) {
		if (mp[n] == 0) mp[n] = ++it;
		flow[mp[n]].pb({i, 1});
	}
}
vector<pii> good;
struct Edge {
	int v, c, r;
};
vector<Edge> edges[205];
int s = 0, t = 1;
void addEdge (int u, int v, int c) {
	edges[u].pb({v, c, (int)edges[v].size()});
	edges[v].pb({u, 0, (int)edges[u].size() - 1});
}
void build (int i) {
	FOR(j, 0, n * 2 + 1, 1) edges[j].clear();
	for (auto p : flow[i]) {
		if (p.fi & 1) addEdge(s, p.fi + 1, p.se);
		else addEdge(p.fi + 1, t, p.se);
	}
	for (auto p : good) {
		if (!(p.fi & 1)) swap(p.fi, p.se);
		addEdge(p.fi + 1, p.se + 1, inf);
	}
}
int dist[205];
bool bfs (int s) {
	queue<int> q;
	SET(dist, -1);
	dist[s] = 0; q.push(s);
	while (!q.empty()) {
		auto u = q.front(); q.pop();
		if (u == t) return true;
		for (auto v : edges[u]) {
			if (!v.c || dist[v.v] != -1) continue;
			dist[v.v] = dist[u] + 1;
			q.push(v.v);
		}
	}
	return false;
}
int dfs (int u, int f) {
	if (u == t) return f;
	int tf = 0;
	for (auto &v : edges[u]) {
		if (!v.c || dist[v.v] != dist[u] + 1) continue;
		int cf = dfs(v.v, min(f, v.c));
		v.c -= cf; edges[v.v][v.r].c += cf;
		tf += cf; f -= cf;
		if (f == 0) break;
	}
	return tf;
}
int dinic () {
	int tf = 0;
	while (bfs(s)) {
		tf += dfs(s, inf);
	}
	return tf;
}
int main () {
	scanf("%d %d", &n, &m);
	sieve(32000);
	FOR(i, 1, n, 1) {
		scanf("%d", &num[i]);
		factorise(num[i], i);
	}
	FOR(i, 1, m, 1) {
		int a, b;
		scanf("%d %d", &a, &b);
		good.pb({a, b});
	}
	int sum = 0;
	FOR(i, 1, it, 1) {
		build(i);
		sum += dinic();
	}
	printf("%d\n", sum);
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define pii pair<int, int>
#define pll pair<ll, ll>
#define fi first
#define se second
#define pb push_back
#define SET(a, b) memset(a, b, sizeof(a))
#define inf 1000000000
#define mod 1000000007
using namespace std;
bool isPrime[32005];
vector<int> prime;
vector<pii> fac[105];
vector<int> id[105];
int it = 0;
void sieve (int n) {
  SET(isPrime, 1); isPrime[0] = isPrime[1] = 0;
  for (int i = 2; i <= n; i++) {
    if (!isPrime[i]) continue;
    prime.pb(i);
    for (int j = i * i; j <= n; j += i) {
      isPrime[j] = 0;
    }
  }
  return;
}
void factorise (int n, int j) {
  for (int k = 0; k < (int)prime.size() && prime[k] <= sqrt(n); k++) {
    int f = prime[k];
    int i = 1;
    while (n % f == 0) {
      n /= f;
      if (i == 1) fac[j].pb({f, 1}), id[j].pb(++it);
      else fac[j][(int)fac[j].size() - 1].se++;
      i++;
    }
  }
  if (n > 1) fac[j].pb({n, 1}), id[j].pb(++it);
  return;
}
vector<int> edges[1105];
int cap[1105][1105];
int s = 1101, t = 1102;
int dist[1105];
bool level (int u) {
	SET(dist, -1);
	queue<int> bfs;
	bfs.push(u); dist[u] = 0;
	while (!bfs.empty()) {
		auto u = bfs.front(); bfs.pop();
		if (u == t) return true;
		for (auto v : edges[u]) {
			if (dist[v] == -1 && cap[u][v]) {
				dist[v] = dist[u] + 1;
				bfs.push(v);
			}
		}
	}
	return false;
}
int dfs (int u, int f) {
	if (u == t) return f;
	int tf = 0;
	for (auto v : edges[u]) {
		if (dist[v] == dist[u] + 1 && cap[u][v]) {
			int cf = dfs(v, min(f, cap[u][v]));
			cap[u][v] -= cf; cap[v][u] += cf;
			tf += cf; f -= cf;
			if (f == 0) break;
		}
	}
	return tf;
}
int main () {
  int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q;
  scanf("%d %d", &a, &b);
  sieve(32000);
  for (i = 1; i <= a; i++) {
    scanf("%d", &c);
    factorise(c, i);
  }
  SET(cap, 0);
  for (i = 1; i <= a; i++) {
  	for (j = 0; (i & 1) && j < fac[i].size(); j++) {
    	edges[s].pb(id[i][j]); edges[id[i][j]].pb(s);
    	cap[s][id[i][j]] += fac[i][j].se;
		}
		for (k = 0; !(i & 1) && k < fac[i].size(); k++) {
			edges[id[i][k]].pb(t); edges[t].pb(id[i][k]);
			cap[id[i][k]][t] += fac[i][k].se;
		}
	}
  for (i = 1; i <= b; i++) {
    scanf("%d %d", &d, &e);
    if (e & 1) swap(d, e);
    for (j = 0, k = 0; j < fac[d].size() && k < fac[e].size(); j++) {
    	while (k < fac[e].size() && fac[e][k].fi < fac[d][j].fi) k++;
    	if (k == fac[e].size()) break;
    	if (fac[d][j].fi == fac[e][k].fi) {
    		edges[id[d][j]].pb(id[e][k]);
    		cap[id[d][j]][id[e][k]] = inf;
    		edges[id[e][k]].pb(id[d][j]);
			}
		}
  }
  int tf = 0;
  while (level(s)) {
  	tf += dfs(s, inf);
	}
	printf("%d\n", tf);
  return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define pii pair<int, int>
#define pll pair<ll, ll>
#define fi first
#define se second
#define pb push_back
#define SET(a, b) memset(a, b, sizeof(a))
#define inf 1000000000
#define llinf 1000000000000000000
#define pi atan(1) * 4
#define eps 1e-6
#define FOR(i, a, b, c) for (int i = (a); i <= (b); i += (c))
#define FORD(i, a, b, c) for (int i = (a); i >= (b); i -= (c))
#define FORl(i, a, b, c) for (ll i = (a); i <= (b); i += (c))
#define FORDl(i, a, b, c) for (ll i = (a); i >= (b); i -= (c))
using namespace std;
int n, m;
bool isPrime[32005];
vector<int> prime;
int num[105];
void sieve (int n) {
	SET(isPrime, 1);
	isPrime[0] = isPrime[1] = 0;
	FOR(i, 2, n, 1) {
		if (!isPrime[i]) continue;
		prime.pb(i);
		FOR(j, i * i, n, i) isPrime[j] = 0;
	}
}
map<int, int> mp;
int it = 0;
vector<pii> flow[3005];
void factorise (int n, int i) {
	for (auto p : prime) {
		if (p * p > n) return;
		int f = 0;
		while (n % p == 0) {
			n /= p; f++;
		}
		if (f) {
			if (mp[p] == 0) mp[p] = ++it;
			flow[mp[p]].pb({i, f});
		}
	}
	if (n != 1) {
		if (mp[n] == 0) mp[n] = ++it;
		flow[mp[n]].pb({i, 1});
	}
}
vector<pii> good;
struct Edge {
	int v, c, r;
};
vector<Edge> edges[205];
int s = 0, t = 1;
void addEdge (int u, int v, int c) {
	edges[u].pb({v, c, (int)edges[v].size()});
	edges[v].pb({u, 0, (int)edges[u].size() - 1});
}
void build (int i) {
	FOR(j, 0, n * 2 + 1, 1) edges[j].clear();
	for (auto p : flow[i]) {
		if (p.fi & 1) addEdge(s, p.fi + 1, p.se);
		else addEdge(p.fi + 1, t, p.se);
	}
	for (auto p : good) {
		if (!(p.fi & 1)) swap(p.fi, p.se);
		addEdge(p.fi + 1, p.se + 1, inf);
	}
}
int dist[205];
bool bfs (int s) {
	queue<int> q;
	SET(dist, -1);
	dist[s] = 0; q.push(s);
	while (!q.empty()) {
		auto u = q.front(); q.pop();
		if (u == t) return true;
		for (auto v : edges[u]) {
			if (!v.c || dist[v.v] != -1) continue;
			dist[v.v] = dist[u] + 1;
			q.push(v.v);
		}
	}
	return false;
}
int dfs (int u, int f) {
	if (u == t) return f;
	int tf = 0;
	for (auto &v : edges[u]) {
		if (!v.c || dist[v.v] != dist[u] + 1) continue;
		int cf = dfs(v.v, min(f, v.c));
		v.c -= cf; edges[v.v][v.r].c += cf;
		tf += cf; f -= cf;
		if (f == 0) break;
	}
	return tf;
}
int dinic () {
	int tf = 0;
	while (bfs(s)) {
		tf += dfs(s, inf);
	}
	return tf;
}
int main () {
	scanf("%d %d", &n, &m);
	sieve(32000);
	FOR(i, 1, n, 1) {
		scanf("%d", &num[i]);
		factorise(num[i], i);
	}
	FOR(i, 1, m, 1) {
		int a, b;
		scanf("%d %d", &a, &b);
		good.pb({a, b});
	}
	int sum = 0;
	FOR(i, 1, it, 1) {
		build(i);
		sum += dinic();
	}
	printf("%d\n", sum);
	return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define pii pair<int, int>
#define pll pair<ll, ll>
#define fi first
#define se second
#define pb push_back
#define SET(a, b) memset(a, b, sizeof(a))
#define inf 1000000000
#define llinf 1000000000000000000
#define pi atan(1) * 4
#define eps 1e-6
#define FOR(i, a, b, c) for (int i = (a); i <= (b); i += (c))
#define FORD(i, a, b, c) for (int i = (a); i >= (b); i -= (c))
#define FORl(i, a, b, c) for (ll i = (a); i <= (b); i += (c))
#define FORDl(i, a, b, c) for (ll i = (a); i >= (b); i -= (c))
using namespace std;
int n, m;
bool isPrime[32005];
vector<int> prime;
int num[105];
void sieve (int n) {
	SET(isPrime, 1);
	isPrime[0] = isPrime[1] = 0;
	FOR(i, 2, n, 1) {
		if (!isPrime[i]) continue;
		prime.pb(i);
		FOR(j, i * i, n, i) isPrime[j] = 0;
	}
}
map<int, int> mp;
int it = 0;
vector<pii> flow[3005];
void factorise (int n, int i) {
	for (auto p : prime) {
		if (p * p > n) return;
		int f = 0;
		while (n % p == 0) {
			n /= p; f++;
		}
		if (f) {
			if (mp[p] == 0) mp[p] = ++it;
			flow[mp[p]].pb({i, f});
		}
	}
	if (n != 1) {
		if (mp[n] == 0) mp[n] = ++it;
		flow[mp[n]].pb({i, 1});
	}
}
vector<pii> good;
struct Edge {
	int v, c, r;
};
vector<Edge> edges[205];
int s = 0, t = 1;
void addEdge (int u, int v, int c) {
	edges[u].pb({v, c, (int)edges[v].size()});
	edges[v].pb({u, 0, (int)edges[u].size() - 1});
}
void build (int i) {
	FOR(j, 0, n * 2 + 1, 1) edges[j].clear();
	for (auto p : flow[i]) {
		if (p.fi & 1) addEdge(s, p.fi + 1, p.se);
		else addEdge(p.fi + 1, t, p.se);
	}
	for (auto p : good) {
		addEdge(p.fi + 1, p.se + 1, inf);
	}
}
int dist[205];
bool bfs (int s) {
	queue<int> q;
	SET(dist, -1);
	dist[s] = 0; q.push(s);
	while (!q.empty()) {
		auto u = q.front(); q.pop();
		if (u == t) return true;
		for (auto v : edges[u]) {
			if (!v.c || dist[v.v] != -1) continue;
			dist[v.v] = dist[u] + 1;
			q.push(v.v);
		}
	}
	return false;
}
int dfs (int u, int f) {
	if (u == t) return f;
	int tf = 0;
	for (auto &v : edges[u]) {
		if (!v.c || dist[v.v] != dist[u] + 1) continue;
		int cf = dfs(v.v, min(f, v.c));
		v.c -= cf; edges[v.v][v.r].c += cf;
		tf += cf; f -= cf;
		if (f == 0) break;
	}
	return tf;
}
int dinic () {
	int tf = 0;
	while (bfs(s)) {
		tf += dfs(s, inf);
	}
	return tf;
}
int main () {
	scanf("%d %d", &n, &m);
	sieve(32000);
	FOR(i, 1, n, 1) {
		scanf("%d", &num[i]);
		factorise(num[i], i);
	}
	FOR(i, 1, m, 1) {
		int a, b;
		scanf("%d %d", &a, &b);
		good.pb({a, b});
	}
	int sum = 0;
	FOR(i, 1, it, 1) {
		build(i);
		sum += dinic();
	}
	printf("%d\n", sum);
	return 0;
}


#include <vector>
#include <iostream>
#include <queue>
using namespace std;

struct Graph {
    struct Edge {
        int from, to, cap, flow, cost;
        Edge(int from, int to, int cap, int cost){
            this->from = from;
            this->to = to;
            this->cap = cap;
            this->cost = cost;
        }
    };

    int n;
    int S, T;
    vector<vector<int> > e;
    vector<Edge> edges;
    vector<int> d, c;

    bool bfs() {
        d.assign(n, 1000000000);
        c.assign(n, 0);
        queue<int> q;
        q.push(S);
        d[S] = 0;
        while (!q.empty()) {
            int v = q.front();
            q.pop();
            for (int i = 0; i < e[v].size(); i++) {
                Edge cur = edges[e[v][i]];
                if (d[cur.to] > d[v] + 1 && -cur.flow + cur.cap > 0) {
                    d[cur.to] = d[v] + 1;
                    q.push(cur.to);
                }
            }
        }
        return d[T] < 1000000000;
    }

    int dfs(int v, int flow) {
        if (flow == 0) return 0;
        if (v == T) return flow;
        for (int &i = c[v]; i < e[v].size(); i++) {
            Edge cur = edges[e[v][i]];
            if (d[cur.to] != d[v] + 1) continue;
            int pushed = dfs(cur.to, min(flow, cur.cap - cur.flow));
            if (pushed) {
                edges[e[v][i]].flow += pushed;
                edges[e[v][i] ^ 1].flow -= pushed;
                return pushed;
            }
        }
        return 0;
    }

    Graph(int N) {
        n = N;
        e.resize(n);
    }

    void addEdge(int from, int to, int cap, int cost = 0) {
        e[from].push_back(edges.size());
        edges.push_back(Edge(from, to, cap, cost));
        e[to].push_back(edges.size());
        edges.push_back(Edge(to, from, 0, -cost));
    }

    long long getFlow(int s, int t) {
        for (int i = 0; i < edges.size(); i++) {
            edges[i].flow = 0;
        }
        S = s;
        T = t;
        long long result = 0;
        while (bfs()) {
            while (int pushed = dfs(S, 1000000000)) {
                result += pushed;
            }
        }
        return result;
    }
};

bool Simple(int x) {
    for (int i = 2; i * i <= x; i++) {
        if (x % i == 0)
            return 0;
    }
	return 1;
}

int n, m;
vector<int> a, u, v;

int solve(int x) {
	Graph gr(n + 2);
	for (int i = 0; i < n; i++) {
		int k = 0;
		while (a[i] % x == 0) {
			a[i] /= x;
			k++;
		}
        if (!k) {
            continue;
        }
		if (i % 2 == 0) {
			gr.addEdge(0, 1 + i / 2, k);
		}
        else {
			gr.addEdge(1 + (n - 1) / 2 + 1 + i / 2, n + 1, k);
		}
	}
    for (int i = 0; i < m; i++) {
        gr.addEdge(1 + u[i] / 2, 1 + (n - 1) / 2 + 1 + v[i] / 2, 1000000000);
    }
	return gr.getFlow(0, n + 1);
}

int main() {
	while (cin >> n >> m) {
		a.resize(n);
		u.resize(m);
		v.resize(m);
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
		for (int i = 0; i < m; i++) {
			cin >> u[i] >> v[i];
			u[i]--;
			v[i]--;
            if (u[i] % 2 == 1) {
                swap(u[i], v[i]);
            }
		}
		int result = 0;
		for (int x = 2; x < 35000; x++) {
			if (Simple(x)) {
				result += solve(x);
			}
		}
		for (int i = 0; i < n; i++) {
			if (a[i] != 1) {
				result += solve(a[i]);
			}
		}
		cout << result << endl;
	}
	return 0;
}

/* Wed May 17 2017 18:36:38 GMT+0300 (MSK) */


#include <cstdio>
#include <iostream>

using namespace std;

int cnt = 0;

bool is_prime(int n){
    if(n == 2) return true;
    if(n % 2 == 0) return false;

    for(int i = 3;i <= n / i;i += 2)
        if(n % i == 0) return false;

    return true;
}

int np = 0,p[70];

int solve(int pos, int l, int r){
    if(pos == np || p[pos] > r) return r - l;
    if(l == r) return 0;++cnt;
    return solve(pos + 1,l,r) - solve(pos + 1,l / p[pos],r / p[pos]);
}

int main(){
    int A,B,k;

    scanf("%d %d %d",&A,&B,&k);

    for(int i = 2;i <= k + 1;++i)
        if(is_prime(i))
         p[np++] = i;

    int ans = solve(0,A,A + B);

    for(int i = 0;i < np;++i)
        if(p[i] > A && p[i] <= A + B)
            ++ans;

    printf("%d",ans);

    return 0;
}
/* Tue Jul 04 2017 21:53:39 GMT+0300 (MSK) */


#include <vector>
#include <iostream>
#include <queue>
using namespace std;

struct Graph {
    struct Edge {
        int from, to, cap, flow, cost;
        Edge(int from, int to, int cap, int cost){
            this->from = from;
            this->to = to;
            this->cap = cap;
            this->cost = cost;
        }
    };

    int n;
    int S, T;
    vector<vector<int> > e;
    vector<Edge> edges;
    vector<int> d, c;

    bool bfs() {
        d.assign(n, 1000000000);
        c.assign(n, 0);
        queue<int> q;
        q.push(S);
        d[S] = 0;
        while (!q.empty()) {
            int v = q.front();
            q.pop();
            for (int i = 0; i < e[v].size(); i++) {
                Edge cur = edges[e[v][i]];
                if (d[cur.to] > d[v] + 1 && -cur.flow + cur.cap > 0) {
                    d[cur.to] = d[v] + 1;
                    q.push(cur.to);
                }
            }
        }
        return d[T] < 1000000000;
    }

    int dfs(int v, int flow) {
        if (flow == 0) {
            return 0;
        }
        if (v == T) {
            return flow;
        }
        for (int &i = c[v]; i < e[v].size(); i++) {
            Edge cur = edges[e[v][i]];
            if (d[cur.to] != d[v] + 1) continue;
            int pushed = dfs(cur.to, min(flow, cur.cap - cur.flow));
            if (pushed) {
                edges[e[v][i]].flow += pushed;
                edges[e[v][i] ^ 1].flow -= pushed;
                return pushed;
            }
        }
        return 0;
    }

    Graph(int N) {
        n = N;
        e.resize(n);
    }

    void addEdge(int from, int to, int cap, int cost = 0) {
        e[from].push_back(edges.size());
        edges.push_back(Edge(from, to, cap, cost));
        e[to].push_back(edges.size());
        edges.push_back(Edge(to, from, 0, -cost));
    }

    long long getFlow(int s, int t) {
        for (int i = 0; i < edges.size(); i++) {
            edges[i].flow = 0;
        }
        S = s;
        T = t;
        long long result = 0;
        while (bfs()) {
            while (int pushed = dfs(S, 1000000000)) {
                result += pushed;
            }
        }
        return result;
    }
};

bool Simple(int x) {
    for (int i = 2; i * i <= x; i++) {
        if (x % i == 0)
            return 0;
    }
	return 1;
}

int n, m;
vector<int> a, u, v;

int solve(int x) {
	Graph gr(n + 2);
	for (int i = 0; i < n; i++) {
		int k = 0;
		while (a[i] % x == 0) {
			a[i] /= x;
			k++;
		}
        if (!k) {
            continue;
        }
		if (i % 2 == 0) {
			gr.addEdge(0, 1 + i / 2, k);
		}
        else {
			gr.addEdge(1 + (n - 1) / 2 + 1 + i / 2, n + 1, k);
		}
	}
    for (int i = 0; i < m; i++) {
        gr.addEdge(1 + u[i] / 2, 1 + (n - 1) / 2 + 1 + v[i] / 2, 1000000000);
    }
	return gr.getFlow(0, n + 1);
}

int main() {
    int n, m;
	cin >> n >> m;
	a.resize(n);
	u.resize(m);
	v.resize(m);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < m; i++) {
		cin >> u[i] >> v[i];
		u[i]--;
		v[i]--;
        if (u[i] % 2 == 1) {
            swap(u[i], v[i]);
        }
    }
	int result = 0;
	for (int x = 2; x < 35000; x++) {
		if (Simple(x)) {
			result += solve(x);
		}
	}
	for (int i = 0; i < n; i++) {
		if (a[i] != 1) {
			result += solve(a[i]);
		}
	}
	cout << result << endl;
	return 0;
}
/* Wed May 17 2017 18:45:37 GMT+0300 (MSK) */


#include <vector>
#include <iostream>
#include <queue>
using namespace std;

struct Graph {
    struct Edge {
        int from, to, cap, flow, cost;
        Edge(int from, int to, int cap, int cost){
            this->from = from;
            this->to = to;
            this->cap = cap;
            this->cost = cost;
        }
    };

    int n;
    int S, T;
    vector<vector<int> > e;
    vector<Edge> edges;
    vector<int> d, c;

    bool bfs() {
        d.assign(n, 1000000000);
        c.assign(n, 0);
        queue<int> q;
        q.push(S);
        d[S] = 0;
        while (!q.empty()) {
            int v = q.front();
            q.pop();
            for (int i = 0; i < e[v].size(); i++) {
                Edge cur = edges[e[v][i]];
                if (d[cur.to] > d[v] + 1 && -cur.flow + cur.cap > 0) {
                    d[cur.to] = d[v] + 1;
                    q.push(cur.to);
                }
            }
        }
        return d[T] < 1000000000;
    }

    int dfs(int v, int flow) {
        if (flow == 0) {
            return 0;
        }
        if (v == T) {
            return flow;
        }
        for (int &i = c[v]; i < e[v].size(); i++) {
            Edge cur = edges[e[v][i]];
            if (d[cur.to] != d[v] + 1) continue;
            int pushed = dfs(cur.to, min(flow, cur.cap - cur.flow));
            if (pushed) {
                edges[e[v][i]].flow += pushed;
                edges[e[v][i] ^ 1].flow -= pushed;
                return pushed;
            }
        }
        return 0;
    }

    Graph(int N) {
        n = N;
        e.resize(n);
    }

    void addEdge(int from, int to, int cap, int cost = 0) {
        e[from].push_back(edges.size());
        edges.push_back(Edge(from, to, cap, cost));
        e[to].push_back(edges.size());
        edges.push_back(Edge(to, from, 0, -cost));
    }

    long long getFlow(int s, int t) {
        for (int i = 0; i < edges.size(); i++) {
            edges[i].flow = 0;
        }
        S = s;
        T = t;
        long long result = 0;
        while (bfs()) {
            while (int pushed = dfs(S, 1000000000)) {
                result += pushed;
            }
        }
        return result;
    }
};

bool Simple(int x) {
    for (int i = 2; i * i <= x; i++) {
        if (x % i == 0)
            return 0;
    }
	return 1;
}

int n, m;
vector<int> a, u, v;

int solve(int x) {
	Graph gr(n + 2);
	for (int i = 0; i < n; i++) {
		int k = 0;
		while (a[i] % x == 0) {
			a[i] /= x;
			k++;
		}
        if (!k) {
            continue;
        }
		if (i % 2 == 0) {
			gr.addEdge(0, 1 + i / 2, k);
		}
        else {
			gr.addEdge(1 + (n - 1) / 2 + 1 + i / 2, n + 1, k);
		}
	}
    for (int i = 0; i < m; i++) {
        gr.addEdge(1 + u[i] / 2, 1 + (n - 1) / 2 + 1 + v[i] / 2, 1000000000);
    }
	return gr.getFlow(0, n + 1);
}

int main() {
	cin >> n >> m;
	a.resize(n);
	u.resize(m);
	v.resize(m);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < m; i++) {
		cin >> u[i] >> v[i];
		u[i]--;
		v[i]--;
        if (u[i] % 2 == 1) {
            swap(u[i], v[i]);
        }
    }
	int result = 0;
	for (int x = 2; x < 35000; x++) {
		if (Simple(x)) {
			result += solve(x);
		}
	}
	for (int i = 0; i < n; i++) {
		if (a[i] != 1) {
			result += solve(a[i]);
		}
	}
	cout << result << endl;
	return 0;
}
/* Wed May 17 2017 18:47:42 GMT+0300 (MSK) */


#include <bits/stdc++.h>
#ifdef BUG
    #include "debug.hpp"
#else
    #define DEBUG(var)
    #define EXPECT(expr)
#endif
#define NO_IO_TIE ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;
template< class T1, class T2 > inline istream &
operator>>( istream & fin, pair< T1, T2 > & pr )
{ fin >> pr.first >> pr.second; return fin; }
template< class T0, class T1, class T2 > inline istream &
operator>>( istream & fin, tuple< T0, T1, T2 > & t )
{ fin >> get<0>(t) >> get<1>(t) >> get<2>(t); return fin; }
template< class T > inline istream &
operator>>( istream & fin, vector< T > & a ) {
if(! a.size()){ size_t n; fin >> n; a.resize( n ); }
for( auto & u: a) fin >> u; return fin; }
/* @@@ ----------------------------------- */

/**
 * maximum flow:
 *      capacities have direction & can be non-symmetric
 *      n: the source node, n + 1 the sink node
 */
typedef struct
{
    const size_t next; /* the other end of edge */
    const int cap; /* capacities have direction & can be non-symmetric */
    int flow; /* flows have sign, are symmetric with diff. signs */
    const size_t i; /* adj[next][i]:self; index of self in adj vector of next*/
} edge_t;

int push_flow( const size_t node,
               const int flow, /* incoming flow */
               vector< vector< edge_t > > & adj,
               vector< bool > & tag )
{
    if( node + 1 == tag.size() ) /* sink node */
        return flow;

    tag[ node ] = true;
    int acc = 0; /* total flow pushed out of this node */

    for( auto & e: adj[ node ] )
        if( ! tag[ e.next ] && e.flow < e.cap )
        {
            const auto fl = min( flow - acc, e.cap - e.flow );
            const auto inc = push_flow( e.next, fl, adj, tag);

            if( inc )
            {
                acc += inc;
                e.flow += inc;
                adj[ e.next ][ e.i ].flow -= inc;

                if( acc == flow )
                    break;
            }
        }

    tag[ node ] = acc == 0;
    return acc;
}

int max_flow( vector< vector< edge_t > > & adj )
{
    /* n: source node,  n + 1: sink node */
    const auto n = adj.size() - 2;

    /* need to tag to avoid looping or visiting a node twice */
    vector< bool > tag( n + 2, false );

    /* push infinite flow to source node */
    const auto inf = numeric_limits< int >::max();
    while( push_flow( n, inf, adj, tag ) )
        ;

    /* add up all to flow out of source node */
    int out = 0;
    for( const auto e: adj[n])
        out += e.flow;

    return out;
}

inline int xdiv( int & a, const int x )
{
    int i;
    for( i = 0; a % x == 0; ++ i, a /= x )
        ;
    return i;
}

inline size_t xsolve( vector< int > & a, const int x,
                      const vector< pair< size_t, size_t > > & e )
{
    const size_t n = a.size();

    vector< int > b( n );
    transform( begin(a), end(a), begin(b),
               bind(xdiv, placeholders::_1, x));

    if( ! * max_element(begin(b), end(b)))
        return 0;

    /* build the graph */
    vector< vector< edge_t > > adj( n + 2 );
    for( const auto & pr : e )
        if( b[ pr.first ] && b[ pr.second ] )
        {
            adj[ pr.first ].push_back( edge_t({ pr.second,
                    min( b[ pr.first ], b[ pr.second ] ),
                    0, adj[ pr.second ].size() }));

            /* caps should be directed !!! */
            adj[ pr.second ].push_back( edge_t({ pr.first, 0, 0,
                        adj[ pr.first ].size() - 1 }));
        }

    /* even nodes are connected to source */
    auto & src = adj[ n ];
    for( size_t i = 0; i < n; i += 2 )
        if( b[ i ] )
        {
            src.push_back( edge_t({ i, b[i], 0, adj[ i ].size() }));
            adj[ i ].push_back( edge_t({ n, 0, 0, src.size() - 1 }));
        }

    /* odd nodes are connected to sink */
    auto & sink = adj[ n + 1 ];
    for( size_t i = 1; i < n; i += 2 )
        if( b[ i ] )
        {
            sink.push_back( edge_t({ i, 0, 0, adj[ i ].size() }));
            adj[ i ].push_back( edge_t({ n + 1, b[ i ], 0, sink.size() - 1 }));
        }

    return max_flow( adj );
}

size_t c498()
{
    size_t n, m;
    cin >> n >> m;
    vector< int > a( n );
    vector< pair< size_t, size_t > > e( m );
    cin >> a >> e;

    for( auto & pr: e )
    {
        -- pr.first;
        -- pr.second;
        if( pr.first & 1 )
            swap( pr.first, pr.second );
    }

    size_t val = xsolve(a, 2, e) + xsolve(a, 3, e);

    const auto ub = 1 + * max_element(begin(a), end(a));

    for( int i = 5; i * i < ub; i += 6)
        val += xsolve(a, i, e) + xsolve(a, i + 2, e);

    for( const auto i: a )
        if( i != 1 )
            val += xsolve(a, i, e);

    return val;
}

int main( const int argc, char * argv [])
{
    // NO_IO_TIE;
    cout << c498();

    return EXIT_SUCCESS;
}


#include <bits/stdc++.h>
#ifdef BUG
    #include "debug.hpp"
#else
    #define DEBUG(var)
    #define EXPECT(expr)
#endif
#define NO_IO_TIE ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;
template< class T1, class T2 > inline istream &
operator>>( istream & fin, pair< T1, T2 > & pr )
{ fin >> pr.first >> pr.second; return fin; }
template< class T0, class T1, class T2 > inline istream &
operator>>( istream & fin, tuple< T0, T1, T2 > & t )
{ fin >> get<0>(t) >> get<1>(t) >> get<2>(t); return fin; }
template< class T > inline istream &
operator>>( istream & fin, vector< T > & a ) {
if(! a.size()){ size_t n; fin >> n; a.resize( n ); }
for( auto & u: a) fin >> u; return fin; }
/* @@@ ----------------------------------- */
// 484e

typedef struct
{
    size_t next;
    int cap, flow; /* cap has `direction`, flow has `sign` */
    size_t i; /* index of self in the `next` adj vector */
} edge_t;

int push_flow( const size_t node,
               const int flow, /* incoming flow */
               vector< vector< edge_t > > & adj,
               vector< bool > & tag )
{
    if( node + 1 == tag.size() ) /* sink node */
        return flow;

    tag[ node ] = true;
    int acc = 0; /* total flow pushed out of this node */

    for( auto & e: adj[ node ] )
        if( ! tag[ e.next ] && e.flow < e.cap )
        {
            const auto fl = min( flow - acc, e.cap - e.flow );
            const auto inc = push_flow( e.next, fl, adj, tag);

            if( inc )
            {
                acc += inc;
                e.flow += inc;
                adj[ e.next ][ e.i ].flow -= inc;

                if( acc == flow )
                    break;
            }
        }

    tag[ node ] = false;
    return acc;
}

int max_flow( vector< vector< edge_t > > & adj )
{
    /* n: source node,  n + 1: sink node */
    const auto n = adj.size() - 2;

    /* need to tag to avoid looping or visiting a node twice */
    vector< bool > tag( n + 2, false );

    /* push infinite flow to source node */
    const auto inf = numeric_limits< int >::max();
    while( push_flow( n, inf, adj, tag ) )
        ;

    /* add up all to flow out of source node */
    int out = 0;
    for( const auto e: adj[n])
        out += e.flow;

    return out;
}

inline int xdiv( int & a, const int x )
{
    int i;
    for( i = 0; a % x == 0; ++ i, a /= x )
        ;
    return i;
}

inline size_t xsolve( vector< int > & a, const int x,
                      const vector< pair< size_t, size_t > > & e )
{
    const size_t n = a.size();

    vector< int > b( n );
    transform( begin(a), end(a), begin(b),
               bind(xdiv, placeholders::_1, x));

    if( ! * max_element(begin(b), end(b)))
        return 0;

    /* build the graph */
    vector< vector< edge_t > > adj( n + 2 );
    for( const auto & pr : e )
        if( b[ pr.first ] && b[ pr.second ] )
        {
            adj[ pr.first ].push_back( edge_t({ pr.second,
                    min( b[ pr.first ], b[ pr.second ] ),
                    0, adj[ pr.second ].size() }));

            /* caps should be directed !!! */
            adj[ pr.second ].push_back( edge_t({ pr.first, 0, 0,
                        adj[ pr.first ].size() - 1 }));
        }

    /* even nodes are connected to source */
    auto & src = adj[ n ];
    for( size_t i = 0; i < n; i += 2 )
        if( b[ i ] )
        {
            src.push_back( edge_t({ i, b[i], 0, adj[ i ].size() }));
            adj[ i ].push_back( edge_t({ n, 0, 0, src.size() - 1 }));
        }

    /* odd nodes are connected to sink */
    auto & sink = adj[ n + 1 ];
    for( size_t i = 1; i < n; i += 2 )
        if( b[ i ] )
        {
            sink.push_back( edge_t({ i, 0, 0, adj[ i ].size() }));
            adj[ i ].push_back( edge_t({ n + 1, b[ i ], 0, sink.size() - 1 }));
        }

    return max_flow( adj );
}

size_t c498()
{
    size_t n, m;
    cin >> n >> m;
    vector< int > a( n );
    vector< pair< size_t, size_t > > e( m );
    cin >> a >> e;

    for( auto & pr: e )
    {
        -- pr.first;
        -- pr.second;
        if( pr.first & 1 )
            swap( pr.first, pr.second );
    }

    size_t val = xsolve(a, 2, e) + xsolve(a, 3, e);

    const auto ub = 1 + * max_element(begin(a), end(a));

    for( int i = 5; i * i < ub; i += 6)
        val += xsolve(a, i, e) + xsolve(a, i + 2, e);

    for( const auto i: a )
        if( i != 1 )
            val += xsolve(a, i, e);

    return val;
}

int main( const int argc, char * argv [])
{
    // NO_IO_TIE;
    cout << c498();

    return EXIT_SUCCESS;
}


#include <bits/stdc++.h>
#ifdef BUG
    #include "debug.hpp"
#else
    #define DEBUG(var)
    #define EXPECT(expr)
#endif
#define NO_IO_TIE ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;
template< class T1, class T2 > inline istream &
operator>>( istream & fin, pair< T1, T2 > & pr )
{ fin >> pr.first >> pr.second; return fin; }
template< class T0, class T1, class T2 > inline istream &
operator>>( istream & fin, tuple< T0, T1, T2 > & t )
{ fin >> get<0>(t) >> get<1>(t) >> get<2>(t); return fin; }
template< class T > inline istream &
operator>>( istream & fin, vector< T > & a ) {
if(! a.size()){ size_t n; fin >> n; a.resize( n ); }
for( auto & u: a) fin >> u; return fin; }
/* @@@ ----------------------------------- */
// 484e

inline int xdiv( int & a, const int x )
{
    int i;
    for( i = 0; a % x == 0; ++ i, a /= x )
        ;
    return i;
}

int walk( const size_t i,
          const int flow_inc, /* flow increment to `this` node */
          const vector< vector< int > > & cap,
          vector< vector< int > > & flow,
          vector< bool > & tag )
{
    if( i + 1 == tag.size() ) /* sink node */
        return flow_inc;

    DEBUG( i );
    DEBUG( flow_inc );

    tag[ i ] = true;

    for( size_t j = 0; j < tag.size(); ++ j )
        if( ! tag[ j ] && flow[ i ][ j ] < cap[ i ][ j ] )
        {
            const auto inc = walk( j,  min(flow_inc, cap[ i ][ j ] - flow[ i ][ j ]),
                    cap, flow, tag );
            if( inc )
            {
                flow[ j ][ i ] -= inc;
                flow[ i ][ j ] += inc;
                tag[ i ] = false;
                return inc;
            }
        }

    tag[ i ] = false;
    return 0;
}

int max_flow( const vector< vector< int > > & cap )
{
    const auto n = cap.size() - 2;
    /* flows are signed */
    vector< vector< int > > flow( n + 2, vector< int >( n + 2 ));
    vector< bool > tag( n + 2, false );

    const auto src = n;
    tag[ src ] = true;

    int val = 0;
    bool fail;

    do
    {
        fail = true;
        for( size_t i = 0; i < n; ++ i )
            if (flow[ src ][ i ] < cap[ src ][ i ] )
            {
                const auto inc = walk( i, cap[ src ][ i ] - flow[ src ][ i ],
                                        cap, flow, tag );

                fail = fail && ! inc;

                flow[ src ][ i ] += inc;
                flow[ i ][ src ] -= inc;

                val += inc;
                DEBUG( inc );
            }
    } while( ! fail );

    return val;
}

inline size_t xsolve( vector< int > & a, const int x,
                      const vector< pair< size_t, size_t > > & e )
{
    const size_t n = a.size();

    vector< int > b( n );
    transform( begin(a), end(a), begin(b),
               bind(xdiv, placeholders::_1, x));

    if( ! * max_element(begin(b), end(b)))
        return 0;

    /* build the graph */
    vector< vector< int > > cap( n + 2, vector< int >( n + 2 ));

    for( const auto & pr : e )
        cap[ pr.first ][ pr.second ]
            = cap[ pr.second ][ pr.first ]
            = min( b[ pr.first ], b[ pr.second ] );

    for( size_t i = 0; i < n; ++ i )
        cap[ n + (i & 1) ][ i ] = cap[ i ][ n + (i & 1) ] = b[ i ];

    DEBUG( cap );

    return max_flow( cap );
}

size_t c498()
{
    size_t n, m;
    cin >> n >> m;
    vector< int > a( n );
    vector< pair< size_t, size_t > > e( m );
    cin >> a >> e;

    for( auto & pr: e )
    {
        -- pr.first;
        -- pr.second;
        if( pr.first & 1 )
            swap( pr.first, pr.second );
    }

    size_t val = xsolve(a, 2, e) + xsolve(a, 3, e);

    const auto ub = 1 + * max_element(begin(a), end(a));

    for( int i = 5; i * i < ub; i += 6)
        val += xsolve(a, i, e) + xsolve(a, i + 2, e);

    for( const auto i: a )
        if( i != 1 )
            val += xsolve(a, i, e);

    return val;
}

int main( const int argc, char * argv [])
{
    // NO_IO_TIE;
    cout << c498();

    return EXIT_SUCCESS;
}


#include <bits/stdc++.h>
#ifdef BUG
    #include "debug.hpp"
#else
    #define DEBUG(var)
    #define EXPECT(expr)
#endif
#define NO_IO_TIE ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;
template< class T1, class T2 > inline istream &
operator>>( istream & fin, pair< T1, T2 > & pr )
{ fin >> pr.first >> pr.second; return fin; }
template< class T0, class T1, class T2 > inline istream &
operator>>( istream & fin, tuple< T0, T1, T2 > & t )
{ fin >> get<0>(t) >> get<1>(t) >> get<2>(t); return fin; }
template< class T > inline istream &
operator>>( istream & fin, vector< T > & a ) {
if(! a.size()){ size_t n; fin >> n; a.resize( n ); }
for( auto & u: a) fin >> u; return fin; }
/* @@@ ----------------------------------- */

/**
 * maximum flow:
 *      capacities have direction & can be non-symmetric
 *      n: the source node, n + 1 the sink node
 */
typedef struct
{
    const size_t next; /* the other end of edge */
    const int cap; /* capacities have direction & can be non-symmetric */
    int flow; /* flows have sign, are symmetric with diff. signs */
    const size_t i; /* adj[next][i]:self; index of self in adj vector of next*/
} edge_t;

int push_flow( const size_t node,
               const int flow, /* incoming flow */
               vector< vector< edge_t > > & adj,
               vector< bool > & tag )
{
    if( node + 1 == tag.size() ) /* sink node */
        return flow;

    tag[ node ] = true;
    int acc = 0; /* total flow pushed out of this node */

    for( auto & e: adj[ node ] )
        if( ! tag[ e.next ] && e.flow < e.cap )
        {
            const auto fl = min( flow - acc, e.cap - e.flow );
            const auto inc = push_flow( e.next, fl, adj, tag);

            if( inc )
            {
                acc += inc;
                e.flow += inc;
                adj[ e.next ][ e.i ].flow -= inc;

                if( acc == flow )
                    break;
            }
        }

    tag[ node ] = acc == 0;
    return acc;
}

int max_flow( vector< vector< edge_t > > & adj )
{
    /* n: source node,  n + 1: sink node */
    const auto n = adj.size() - 2;

    /* need to tag to avoid looping or visiting a node twice */
    vector< bool > tag( n + 2, false );

    /* push infinite flow to source node */
    const auto inf = numeric_limits< int >::max();
    while( push_flow( n, inf, adj, tag ) )
        fill(begin(tag), end(tag), false);

    /* add up all to flow out of source node */
    int out = 0;
    for( const auto e: adj[n])
        out += e.flow;

    return out;
}

inline int xdiv( int & a, const int x )
{
    int i;
    for( i = 0; a % x == 0; ++ i, a /= x )
        ;
    return i;
}

inline size_t xsolve( vector< int > & a, const int x,
                      const vector< pair< size_t, size_t > > & e )
{
    const size_t n = a.size();

    vector< int > b( n );
    transform( begin(a), end(a), begin(b),
               bind(xdiv, placeholders::_1, x));

    if( ! * max_element(begin(b), end(b)))
        return 0;

    /* build the graph */
    vector< vector< edge_t > > adj( n + 2 );
    for( const auto & pr : e )
        if( b[ pr.first ] && b[ pr.second ] )
        {
            adj[ pr.first ].push_back( edge_t({ pr.second,
                    min( b[ pr.first ], b[ pr.second ] ),
                    0, adj[ pr.second ].size() }));

            /* caps should be directed !!! */
            adj[ pr.second ].push_back( edge_t({ pr.first, 0, 0,
                        adj[ pr.first ].size() - 1 }));
        }

    /* even nodes are connected to source */
    auto & src = adj[ n ];
    for( size_t i = 0; i < n; i += 2 )
        if( b[ i ] )
        {
            src.push_back( edge_t({ i, b[i], 0, adj[ i ].size() }));
            adj[ i ].push_back( edge_t({ n, 0, 0, src.size() - 1 }));
        }

    /* odd nodes are connected to sink */
    auto & sink = adj[ n + 1 ];
    for( size_t i = 1; i < n; i += 2 )
        if( b[ i ] )
        {
            sink.push_back( edge_t({ i, 0, 0, adj[ i ].size() }));
            adj[ i ].push_back( edge_t({ n + 1, b[ i ], 0, sink.size() - 1 }));
        }

    return max_flow( adj );
}

size_t c498()
{
    size_t n, m;
    cin >> n >> m;
    vector< int > a( n );
    vector< pair< size_t, size_t > > e( m );
    cin >> a >> e;

    for( auto & pr: e )
    {
        -- pr.first;
        -- pr.second;
        if( pr.first & 1 )
            swap( pr.first, pr.second );
    }

    size_t val = xsolve(a, 2, e) + xsolve(a, 3, e);

    const auto ub = 1 + * max_element(begin(a), end(a));

    for( int i = 5; i * i < ub; i += 6)
        val += xsolve(a, i, e) + xsolve(a, i + 2, e);

    for( const auto i: a )
        if( i != 1 )
            val += xsolve(a, i, e);

    return val;
}

int main( const int argc, char * argv [])
{
    // NO_IO_TIE;
    cout << c498();

    return EXIT_SUCCESS;
}


#include <bits/stdc++.h>
#ifdef BUG
    #include "debug.hpp"
#else
    #define DEBUG(var)
    #define EXPECT(expr)
#endif
#define NO_IO_TIE ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;
template< class T1, class T2 > inline istream &
operator>>( istream & fin, pair< T1, T2 > & pr )
{ fin >> pr.first >> pr.second; return fin; }
template< class T0, class T1, class T2 > inline istream &
operator>>( istream & fin, tuple< T0, T1, T2 > & t )
{ fin >> get<0>(t) >> get<1>(t) >> get<2>(t); return fin; }
template< class T > inline istream &
operator>>( istream & fin, vector< T > & a ) {
if(! a.size()){ size_t n; fin >> n; a.resize( n ); }
for( auto & u: a) fin >> u; return fin; }
/* @@@ ----------------------------------- */
// 484e

inline int xdiv( int & a, const int x )
{
    int i;
    for( i = 0; a % x == 0; ++ i, a /= x )
        ;
    return i;
}

int walk( const size_t i,
          const int flow_inc, /* flow increment to `this` node */
          const vector< vector< int > > & cap,
          vector< vector< int > > & flow,
          vector< bool > & tag )
{
    if( i + 1 == tag.size() ) /* sink node */
        return flow_inc;

    tag[ i ] = true;

    for( size_t j = 0; j < tag.size(); ++ j )
        if( ! tag[ j ] && flow[ i ][ j ] < cap[ i ][ j ] )
        {
            const auto inc = walk( j,  min(flow_inc, cap[ i ][ j ] - flow[ i ][ j ]),
                    cap, flow, tag );
            if( inc )
            {
                flow[ i ][ j ] += inc;
                flow[ j ][ i ] -= inc;
                tag[ i ] = false;
                return inc;
            }
        }

    tag[ i ] = false;
    return 0;
}

int max_flow( const vector< vector< int > > & cap )
{
    const auto n = cap.size() - 2;
    /* flows are signed */
    vector< vector< int > > flow( n + 2, vector< int >( n + 2 ));
    vector< bool > tag( n + 2, false );

    const auto src = n;
    tag[ src ] = true;

    int val = 0;
    bool fail;

    do
    {
        fail = true;
        for( size_t i = 0; i < n; ++ i )
            if (flow[ src ][ i ] < cap[ src ][ i ] )
            {
                const auto inc = walk( i, cap[ src ][ i ] - flow[ src ][ i ],
                                        cap, flow, tag );

                fail = fail && ! inc;

                flow[ src ][ i ] += inc;
                flow[ i ][ src ] -= inc;

                val += inc;
                DEBUG( inc );
            }
    } while( ! fail );

    DEBUG( flow );
    return val;
}

inline size_t xsolve( vector< int > & a, const int x,
                      const vector< pair< size_t, size_t > > & e )
{
    const size_t n = a.size();

    vector< int > b( n );
    transform( begin(a), end(a), begin(b),
               bind(xdiv, placeholders::_1, x));

    if( ! * max_element(begin(b), end(b)))
        return 0;

    /* build the graph */
    vector< vector< int > > cap( n + 2, vector< int >( n + 2 ));

    for( const auto & pr : e )
        cap[ pr.first ][ pr.second ]
            // = cap[ pr.second ][ pr.first ]
            = min( b[ pr.first ], b[ pr.second ] );

    for( size_t i = 0; i < n; ++ i )
        cap[ n + (i & 1) ][ i ] = cap[ i ][ n + (i & 1) ] = b[ i ];

    DEBUG( cap );

    return max_flow( cap );
}

size_t c498()
{
    size_t n, m;
    cin >> n >> m;
    vector< int > a( n );
    vector< pair< size_t, size_t > > e( m );
    cin >> a >> e;

    for( auto & pr: e )
    {
        -- pr.first;
        -- pr.second;
        if( pr.first & 1 )
            swap( pr.first, pr.second );
    }

    size_t val = xsolve(a, 2, e) + xsolve(a, 3, e);

    const auto ub = 1 + * max_element(begin(a), end(a));

    for( int i = 5; i * i < ub; i += 6)
        val += xsolve(a, i, e) + xsolve(a, i + 2, e);

    for( const auto i: a )
        if( i != 1 )
            val += xsolve(a, i, e);

    return val;
}

int main( const int argc, char * argv [])
{
    // NO_IO_TIE;
    cout << c498();

    return EXIT_SUCCESS;
}


#include <bits/stdc++.h>
#ifdef BUG
    #include "debug.hpp"
#else
    #define DEBUG(var)
    #define EXPECT(expr)
#endif
#define NO_IO_TIE ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);

using namespace std;
template< class T1, class T2 > inline istream &
operator>>( istream & fin, pair< T1, T2 > & pr )
{ fin >> pr.first >> pr.second; return fin; }
template< class T0, class T1, class T2 > inline istream &
operator>>( istream & fin, tuple< T0, T1, T2 > & t )
{ fin >> get<0>(t) >> get<1>(t) >> get<2>(t); return fin; }
template< class T > inline istream &
operator>>( istream & fin, vector< T > & a ) {
if(! a.size()){ size_t n; fin >> n; a.resize( n ); }
for( auto & u: a) fin >> u; return fin; }
/* @@@ ----------------------------------- */

/**
 * maximum flow:
 *      capacities have direction & can be non-symmetric
 *      n: the source node, n + 1 the sink node
 */
typedef struct
{
    const size_t next; /* the other end of edge */
    const int cap; /* capacities have direction & can be non-symmetric */
    int flow; /* flows have sign, are symmetric with diff. signs */
    const size_t i; /* adj[next][i]:self; index of self in adj vector of next*/
} edge_t;

int push_flow( const size_t node,
               const int flow, /* incoming flow */
               vector< vector< edge_t > > & adj,
               vector< bool > & tag )
{
    if( node + 1 == tag.size() ) /* sink node */
        return flow;

    tag[ node ] = true;
    int acc = 0; /* total flow pushed out of this node */

    for( auto & e: adj[ node ] )
        if( ! tag[ e.next ] && e.flow < e.cap )
        {
            const auto fl = min( flow - acc, e.cap - e.flow );
            const auto inc = push_flow( e.next, fl, adj, tag);

            if( inc )
            {
                acc += inc;
                e.flow += inc;
                adj[ e.next ][ e.i ].flow -= inc;

                if( acc == flow )
                    break;
            }
        }

    tag[ node ] = false;
    return acc;
}

int max_flow( vector< vector< edge_t > > & adj )
{
    /* n: source node,  n + 1: sink node */
    const auto n = adj.size() - 2;

    /* need to tag to avoid looping or visiting a node twice */
    vector< bool > tag( n + 2, false );

    /* push infinite flow to source node */
    const auto inf = numeric_limits< int >::max();
    while( push_flow( n, inf, adj, tag ) )
        ;

    /* add up all to flow out of source node */
    int out = 0;
    for( const auto e: adj[n])
        out += e.flow;

    return out;
}

inline int xdiv( int & a, const int x )
{
    int i;
    for( i = 0; a % x == 0; ++ i, a /= x )
        ;
    return i;
}

inline size_t xsolve( vector< int > & a, const int x,
                      const vector< pair< size_t, size_t > > & e )
{
    const size_t n = a.size();

    vector< int > b( n );
    transform( begin(a), end(a), begin(b),
               bind(xdiv, placeholders::_1, x));

    if( ! * max_element(begin(b), end(b)))
        return 0;

    /* build the graph */
    vector< vector< edge_t > > adj( n + 2 );
    for( const auto & pr : e )
        if( b[ pr.first ] && b[ pr.second ] )
        {
            adj[ pr.first ].push_back( edge_t({ pr.second,
                    min( b[ pr.first ], b[ pr.second ] ),
                    0, adj[ pr.second ].size() }));

            /* caps should be directed !!! */
            adj[ pr.second ].push_back( edge_t({ pr.first, 0, 0,
                        adj[ pr.first ].size() - 1 }));
        }

    /* even nodes are connected to source */
    auto & src = adj[ n ];
    for( size_t i = 0; i < n; i += 2 )
        if( b[ i ] )
        {
            src.push_back( edge_t({ i, b[i], 0, adj[ i ].size() }));
            adj[ i ].push_back( edge_t({ n, 0, 0, src.size() - 1 }));
        }

    /* odd nodes are connected to sink */
    auto & sink = adj[ n + 1 ];
    for( size_t i = 1; i < n; i += 2 )
        if( b[ i ] )
        {
            sink.push_back( edge_t({ i, 0, 0, adj[ i ].size() }));
            adj[ i ].push_back( edge_t({ n + 1, b[ i ], 0, sink.size() - 1 }));
        }

    return max_flow( adj );
}

size_t c498()
{
    size_t n, m;
    cin >> n >> m;
    vector< int > a( n );
    vector< pair< size_t, size_t > > e( m );
    cin >> a >> e;

    for( auto & pr: e )
    {
        -- pr.first;
        -- pr.second;
        if( pr.first & 1 )
            swap( pr.first, pr.second );
    }

    size_t val = xsolve(a, 2, e) + xsolve(a, 3, e);

    const auto ub = 1 + * max_element(begin(a), end(a));

    for( int i = 5; i * i < ub; i += 6)
        val += xsolve(a, i, e) + xsolve(a, i + 2, e);

    for( const auto i: a )
        if( i != 1 )
            val += xsolve(a, i, e);

    return val;
}

int main( const int argc, char * argv [])
{
    // NO_IO_TIE;
    cout << c498();

    return EXIT_SUCCESS;
}


// In The Name Of God
#include <iostream>
#include <string.h>
#include <algorithm>
#include <set>
#include <vector>
#include <climits>
#include <map>
#include <queue>
#include <math.h>
#include <iomanip>
#include <unordered_map>

#define sqr(A) ((A) * (A))
#define F first
#define S second
#define MP make_pair
#define bsz  __builtin_popcount
#define all(A) A.begin(), A.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
const int MOD = 1e9 + 7;
const int MOD2 = 1e9 + 9;
const int PR = 727;
const int INF = INT_MAX;
const ll LINF = LLONG_MAX;

const int N = 1e2 + 20;
unordered_map<int, int> p[N];
vector<int> pr;
vector<pii> e;
int a[N], n, m, ans;
int capacity[N][N];

class MaxFlow {
	bool visited[N];
	int from[N];

	int get_path(int n, int s, int f) {
		memset(from, -1, sizeof from);
		memset(visited, 0, sizeof visited);
		queue<int> q;
		q.push(s);
		visited[s] = 1;
		while (q.size()) {
			int v = q.front(); q.pop();
			bool sink_found = 0;
			for (int u = 0; u <= n; u++)
				if (!visited[u] && capacity[v][u] > 0) {
					visited[u] = 1;
					from[u] = v;
					q.push(u);
					if (u == f) {
						sink_found = 1;
						break;
					}
				}
			if (sink_found)
				break;
		}
		int cur = f, result = INF;
		while (from[cur] != -1) {
			int prev = from[cur];
			result = min(result, capacity[prev][cur]);
			cur = prev;
		}
		cur = f;
		while (from[cur] != -1) {
			int prev = from[cur];
			capacity[prev][cur] -= result;
			capacity[cur][prev] += result;
			cur = prev;
		}
		if (result == INF)
			return 0;
		else
			return result;
	}

public:
	int max_flow(int n, int s, int f) {
		int result = 0;
		while (true) {
			int path = get_path(n, s, f);
			if (path == 0)
				break;
			else
				result += path;
		}
		return result;
	}
};

ll phi(ll x) {
    ll res = x;
    for (ll i = 2; i * i <= x; i++) {
        if (x % i == 0) {
            while (x % i == 0)
                x /= i;
            res -= res / i;
        }
    }
    if (x > 1)
        res -= res / x;
    return res;
}

bool is_prime(ll x) {
	return phi(x) == x - 1;
}

MaxFlow maxflow;

int main() {
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		int tmp = a[i];
		for (int j = 2; j <= sqrt(a[i]) + 1; j++) {
			if (j > tmp || tmp == 1) break;
			if (tmp % j == 0) {
				if (is_prime(j)) {
					pr.push_back(j);
					while (tmp % j == 0) {
						p[i][j]++;
						tmp /= j;
					}
				}
				tmp = a[i];
				int r = tmp / j;
				if (is_prime(r)) {
					pr.push_back(r);
					while (tmp % r == 0) {
						p[i][r]++;
						tmp /= r;
					}
				}
			}
		}
	}
	for (int i = 0, v, u; i < m; i++) {
		cin >> v >> u;
		e.push_back(MP(v, u));
	}
	sort(all(pr));
	pr.resize( unique(all(pr)) - pr.begin() );
	for (int f : pr) {
		for (auto t : e) {
			int v = t.F, u = t.S;
			if (v % 2) swap(v, u);
			capacity[v][u] = p[u][f];
		}
		for (int i = 2; i <= n; i += 2)
			capacity[0][i] = p[i][f];
		for (int i = 1; i <= n; i += 2)
			capacity[i][n + 1] = p[i][f];
		ans += maxflow.max_flow(n + 1, 0, n + 1);
	}
	cout << ans << endl;
}


// In The Name Of God
#include <iostream>
#include <string.h>
#include <algorithm>
#include <set>
#include <vector>
#include <climits>
#include <map>
#include <queue>
#include <math.h>
#include <iomanip>
#include <unordered_map>

#define sqr(A) ((A) * (A))
#define F first
#define S second
#define MP make_pair
#define bsz  __builtin_popcount
#define all(A) A.begin(), A.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
const int MOD = 1e9 + 7;
const int MOD2 = 1e9 + 9;
const int PR = 727;
const int INF = INT_MAX;
const ll LINF = LLONG_MAX;

const int N = 1e2 + 20;
unordered_map<int, int> p[N];
vector<int> pr;
vector<pii> e;
int a[N], n, m, ans;
int capacity[N][N];

class MaxFlow {
	bool visited[N];
	int from[N];

	int get_path(int n, int s, int f) {
		memset(from, -1, sizeof from);
		memset(visited, 0, sizeof visited);
		queue<int> q;
		q.push(s);
		visited[s] = 1;
		while (q.size()) {
			int v = q.front(); q.pop();
			bool sink_found = 0;
			for (int u = 0; u <= n; u++)
				if (!visited[u] && capacity[v][u] > 0) {
					visited[u] = 1;
					from[u] = v;
					q.push(u);
					if (u == f) {
						sink_found = 1;
						break;
					}
				}
			if (sink_found)
				break;
		}
		int cur = f, result = INF;
		while (from[cur] != -1) {
			int prev = from[cur];
			result = min(result, capacity[prev][cur]);
			cur = prev;
		}
		cur = f;
		while (from[cur] != -1) {
			int prev = from[cur];
			capacity[prev][cur] -= result;
			capacity[cur][prev] += result;
			cur = prev;
		}
		if (result == INF)
			return 0;
		else
			return result;
	}

public:
	int max_flow(int n, int s, int f) {
		int result = 0;
		while (true) {
			int path = get_path(n, s, f);
			if (path == 0)
				break;
			else
				result += path;
		}
		return result;
	}
};

ll phi(ll x) {
    ll res = x;
    for (ll i = 2; i * i <= x; i++) {
        if (x % i == 0) {
            while (x % i == 0)
                x /= i;
            res -= res / i;
        }
    }
    if (x > 1)
        res -= res / x;
    return res;
}

bool is_prime(ll x) {
	return phi(x) == x - 1;
}

MaxFlow maxflow;

int main() {
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		int tmp = a[i];
		for (int j = 2; j <= sqrt(a[i]); j++) {
			if (j > tmp || tmp == 1) break;
			if (tmp % j == 0 && is_prime(j)) {
				pr.push_back(j);
				while (tmp % j == 0) {
					p[i][j]++;
					tmp /= j;
				}
			}
		}
	}
	for (int i = 0, v, u; i < m; i++) {
		cin >> v >> u;
		e.push_back(MP(v, u));
	}
	sort(all(pr));
	pr.resize( unique(all(pr)) - pr.begin() );
	for (int f : pr) {
		for (auto t : e) {
			int v = t.F, u = t.S;
			if (v % 2) swap(v, u);
			capacity[v][u] = p[u][f];
		}
		for (int i = 2; i <= n; i += 2)
			capacity[0][i] = p[i][f];
		for (int i = 1; i <= n; i += 2)
			capacity[i][n + 1] = INF;
		ans += maxflow.max_flow(n + 1, 0, n + 1);
	}
	cout << ans << endl;
}


// In The Name Of God
#include <iostream>
#include <string.h>
#include <algorithm>
#include <set>
#include <vector>
#include <climits>
#include <map>
#include <queue>
#include <math.h>
#include <iomanip>
#include <unordered_map>

#define sqr(A) ((A) * (A))
#define F first
#define S second
#define MP make_pair
#define bsz  __builtin_popcount
#define all(A) A.begin(), A.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
const int MOD = 1e9 + 7;
const int MOD2 = 1e9 + 9;
const int PR = 727;
const int INF = INT_MAX;
const ll LINF = LLONG_MAX;

const int N = 1e2 + 20;
unordered_map<int, int> p[N];
vector<int> pr;
vector<pii> e;
int a[N], n, m, ans;
int capacity[N][N];

class MaxFlow {
	bool visited[N];
	int from[N];

	int get_path(int n, int s, int f) {
		memset(from, -1, sizeof from);
		memset(visited, 0, sizeof visited);
		queue<int> q;
		q.push(s);
		visited[s] = 1;
		while (q.size()) {
			int v = q.front(); q.pop();
			bool sink_found = 0;
			for (int u = 0; u <= n; u++)
				if (!visited[u] && capacity[v][u] > 0) {
					visited[u] = 1;
					from[u] = v;
					q.push(u);
					if (u == f) {
						sink_found = 1;
						break;
					}
				}
			if (sink_found)
				break;
		}
		int cur = f, result = INF;
		while (from[cur] != -1) {
			int prev = from[cur];
			result = min(result, capacity[prev][cur]);
			cur = prev;
		}
		cur = f;
		while (from[cur] != -1) {
			int prev = from[cur];
			capacity[prev][cur] -= result;
			capacity[cur][prev] += result;
			cur = prev;
		}
		if (result == INF)
			return 0;
		else
			return result;
	}

public:
	int max_flow(int n, int s, int f) {
		int result = 0;
		while (true) {
			int path = get_path(n, s, f);
			if (path == 0)
				break;
			else
				result += path;
		}
		return result;
	}
};

ll phi(ll x) {
    ll res = x;
    for (ll i = 2; i * i <= x; i++) {
        if (x % i == 0) {
            while (x % i == 0)
                x /= i;
            res -= res / i;
        }
    }
    if (x > 1)
        res -= res / x;
    return res;
}

bool is_prime(ll x) {
	return phi(x) == x - 1;
}

MaxFlow maxflow;

int main() {
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		int tmp = a[i];
		for (int j = 1; j * j <= a[i]; j++) {
			if (tmp == 1) break;
			int A = j, B = a[i] / j;
			if (tmp % A == 0 && is_prime(A)) {
				pr.push_back(A);
				while (tmp % A == 0) {
					tmp /= A;
					p[i][A]++;
				}
			}
			if (tmp % B == 0 && is_prime(B)) {
				pr.push_back(B);
				while (tmp % B == 0) {
					tmp /= B;
					p[i][B]++;
				}
			}
		}
	}
	for (int i = 0, v, u; i < m; i++) {
		cin >> v >> u;
		e.push_back(MP(v, u));
	}
	sort(all(pr));
	pr.resize( unique(all(pr)) - pr.begin() );
	for (int f : pr) {
		for (auto t : e) {
			int v = t.F, u = t.S;
			if (v % 2) swap(v, u);
			capacity[v][u] = p[u][f];
		}
		for (int i = 2; i <= n; i += 2)
			capacity[0][i] = p[i][f];
		for (int i = 1; i <= n; i += 2)
			capacity[i][n + 1] = p[i][f];
		ans += maxflow.max_flow(n + 1, 0, n + 1);
	}
	cout << ans << endl;
}


// In The Name Of God
#include <iostream>
#include <string.h>
#include <algorithm>
#include <set>
#include <vector>
#include <climits>
#include <map>
#include <queue>
#include <math.h>
#include <iomanip>
#include <unordered_map>

#define sqr(A) ((A) * (A))
#define F first
#define S second
#define MP make_pair
#define bsz  __builtin_popcount
#define all(A) A.begin(), A.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
const int MOD = 1e9 + 7;
const int MOD2 = 1e9 + 9;
const int PR = 727;
const int INF = INT_MAX;
const ll LINF = LLONG_MAX;

const int N = 1e2 + 20;
unordered_map<int, int> p[N];
vector<int> pr;
vector<pii> e;
int a[N], n, m, ans;
int capacity[N][N];

class MaxFlow {
	bool visited[N];
	int from[N];

	int get_path(int n, int s, int f) {
		memset(from, -1, sizeof from);
		memset(visited, 0, sizeof visited);
		queue<int> q;
		q.push(s);
		visited[s] = 1;
		while (q.size()) {
			int v = q.front(); q.pop();
			bool sink_found = 0;
			for (int u = 0; u <= n; u++)
				if (!visited[u] && capacity[v][u] > 0) {
					visited[u] = 1;
					from[u] = v;
					q.push(u);
					if (u == f) {
						sink_found = 1;
						break;
					}
				}
			if (sink_found)
				break;
		}
		int cur = f, result = INF;
		while (from[cur] != -1) {
			int prev = from[cur];
			result = min(result, capacity[prev][cur]);
			cur = prev;
		}
		cur = f;
		while (from[cur] != -1) {
			int prev = from[cur];
			capacity[prev][cur] -= result;
			capacity[cur][prev] += result;
			cur = prev;
		}
		if (result == INF)
			return 0;
		else
			return result;
	}

public:
	int max_flow(int n, int s, int f) {
		int result = 0;
		while (true) {
			int path = get_path(n, s, f);
			if (path == 0)
				break;
			else
				result += path;
		}
		return result;
	}
};

ll phi(ll x) {
    ll res = x;
    for (ll i = 2; i * i <= x; i++) {
        if (x % i == 0) {
            while (x % i == 0)
                x /= i;
            res -= res / i;
        }
    }
    if (x > 1)
        res -= res / x;
    return res;
}

bool is_prime(ll x) {
	return phi(x) == x - 1;
}

MaxFlow maxflow;

int main() {
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		int tmp = a[i];
		for (int j = 2; j <= sqrt(a[i]); j++) {
			if (j > tmp || tmp == 1) break;
			if (tmp % j == 0 && is_prime(j)) {
				pr.push_back(j);
				while (tmp % j == 0) {
					p[i][j]++;
					tmp /= j;
				}
			}
		}
	}
	for (int i = 0, v, u; i < m; i++) {
		cin >> v >> u;
		e.push_back(MP(v, u));
	}
	sort(all(pr));
	pr.resize( unique(all(pr)) - pr.begin() );
	for (int f : pr) {
		for (auto t : e) {
			int v = t.F, u = t.S;
			if (v % 2) swap(v, u);
			capacity[v][u] = p[u][f];
		}
		for (int i = 2; i <= n; i += 2)
			capacity[0][i] = p[i][f];
		for (int i = 1; i <= n; i += 2)
			capacity[i][n + 1] = p[i][f];
		ans += maxflow.max_flow(n + 1, 0, n + 1);
	}
	cout << ans << endl;
}


#include <bits/stdc++.h>
using namespace std;
#pragma GCC diagnostic warning "-std=c++11"

using ll = long long;
using ull = unsigned long long;
const ll mod = 1e9 + 7;

#define sqr( a ) ( ( a ) * ( a ) )
const int inf = 5e6;

const int INF = 1e9;

struct Edge {
        int from, to, cap, flow, index;
        Edge(int from, int to, int cap, int flow, int index) :
                from(from), to(to), cap(cap), flow(flow), index(index) {}
};

struct Dinic {
        int N;
        vector<vector<Edge> > G;
        vector<Edge *> dad;
        vector<int> Q;

        Dinic(int N) : N(N), G(N), dad(N), Q(N) {}

        void add_edge(int from, int to, int cap) {
                G[from].push_back(Edge(from, to, cap, 0, G[to].size()));
                if (from == to) G[from].back().index++;
                G[to].push_back(Edge(to, from, 0, 0, G[from].size() - 1));
        }

        long long blocking_flow(int s, int t) {
                fill(dad.begin(), dad.end(), (Edge *) NULL);
                dad[s] = &G[0][0] - 1;

                int head = 0, tail = 0;
                Q[tail++] = s;
                while (head < tail) {
                        int x = Q[head++];
                        for (int i = 0; i < G[x].size(); i++) {
                                Edge &e = G[x][i];
                                if (!dad[e.to] && e.cap - e.flow > 0) {
                                        dad[e.to] = &G[x][i];
                                        Q[tail++] = e.to;
                                }
                        }
                }
                if (!dad[t]) return 0;

                long long totflow = 0;
                for (int i = 0; i < G[t].size(); i++) {
                        Edge *start = &G[G[t][i].to][G[t][i].index];
                        int amt = INF;
                        for (Edge *e = start; amt && e != dad[s]; e = dad[e->from]) {
                                if (!e) {
                                        amt = 0;
                                        break;
                                }
                                amt = min(amt, e->cap - e->flow);
                        }
                        if (amt == 0) continue;
                        for (Edge *e = start; amt && e != dad[s]; e = dad[e->from]) {
                                e->flow += amt;
                                G[e->to][e->index].flow -= amt;
                        }
                        totflow += amt;
                }
                return totflow;
        }

        long long max_flow(int s, int t) {
                long long totflow = 0;
                while (long long flow = blocking_flow(s, t))
                        totflow += flow;
                return totflow;
        }

        void clear_flow() {
                for (int i = 0; i < N; ++i)
                        for (int j = 0; j < G[i].size(); ++j)
                                G[i][j].flow = 0;

        }
};

const int sz = 5e4 + 10;
int n, m;
vector < int > G[105];
int src, sink;
int tot_v;
vector < int > pr;
bitset < sz > fl;
int fac[sz];

void siv() {
        for( int i=4; i<sz; i+=2 ) fl[i] = 1;
        for( int i=3; i*i<sz; i+=2 ) {
                if( fl[i] ) continue;
                for( int j=i*i; j<sz; j+=i ) fl[j] = 1;
        }
        pr.push_back( 2 );
        for( int i=3; i<sz; i+=2 ) if( fl[i] == 0 ) pr.push_back( i );
}

void factorise( int i, int num ) {
        for( const int x: pr ) {
                while( num % x == 0 ) {
                        num /= x;
                        tot_v++;
                        G[i].push_back( tot_v );
                        fac[tot_v] = x;
                }
        }
}

int main() {
#ifdef CLown1331
        freopen( "in.txt","r",stdin );
#endif /// CLown1331

        siv();

        while( cin >> n >> m ) {

                tot_v = 0;

                for( int i=0; i<n; i++ ) {
                        G[i].clear();
                        int x;
                        cin >> x;
                        factorise( i, x );
                }

                src = 0;

                sink = tot_v + 1;

                Dinic graph( sink + 1 );

                while( m-- ) {
                        int x, y;
                        cin >> x >> y;
                        --x, --y;
                        if( x & 1 ) swap( x, y );
                        for( const int& u: G[x] ) {
                                for( const int& v: G[y] ) {
                                        if( fac[u] == fac[v] ) graph.add_edge( u, v, 1 );
                                }
                        }
                }

                for( int i=0; i<n; i++ ) {
                        for( const int& u: G[i] ) graph.add_edge( i & 1 ? u : src, i & 1 ? sink : u, i & 1 ? 1 : INF );
                }

                cout << graph.max_flow( src, sink ) << "\n";

                cerr << "-----\n";
        }

        return 0;
}


#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int ar[105], n, m, ans, gcd;
pair < int, int > vp[105];

void nod() {
    for( int i=2; i*i<=gcd; i++ ) {
        if( gcd % i == 0 ) {
            ans++;
            if( gcd / i != i ) {
                ans++;
            }
        }
    }
    if( gcd != 1 ) ans++;
}

int main() {
    #ifdef CLown1331
        freopen( "in.txt","r",stdin );
    #endif /// CLown1331
    while( cin >> n >> m ) {
        for( int i=1; i<=n; i++ ) {
            cin >> ar[i];
        }
        ans = 0;
        for( int i=0; i<m; i++ ) {
            cin >> vp[i].first >> vp[i].second;
            gcd = __gcd( ar[ vp[i].first ], ar[ vp[i].second ] );
            ar[ vp[i].first ] /= gcd;
            ar[ vp[i].second ] /= gcd;
            nod();
        }
        cout << ans << "\n";
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int ar[105], n, m, ans, gcd;
pair < int, int > vp[105];

void nod() {
    for( int i=2; i*i<=gcd; i++ ) {
        if( gcd % i == 0 ) {
            ans++;
            if( gcd / i != i ) {
                ans++;
            }
        }
    }
}

int main() {
    #ifdef CLown1331
        freopen( "in.txt","r",stdin );
    #endif /// CLown1331
    while( cin >> n >> m ) {
        for( int i=1; i<=n; i++ ) {
            cin >> ar[i];
        }
        ans = 0;
        for( int i=0; i<m; i++ ) {
            cin >> vp[i].first >> vp[i].second;
            gcd = __gcd( ar[ vp[i].first ], ar[ vp[i].second ] );
            nod();
        }
        cout << ans << "\n";
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#pragma GCC diagnostic warning "-std=c++11"

using ll = long long;
using ull = unsigned long long;
const ll mod = 1e9 + 7;

#define sqr( a ) ( ( a ) * ( a ) )
const int inf = 5e6;

const int INF = 1e9;

struct Edge {
        int from, to, cap, flow, index;
        Edge(int from, int to, int cap, int flow, int index) :
                from(from), to(to), cap(cap), flow(flow), index(index) {}
};

struct Dinic {
        int N;
        vector<vector<Edge> > G;
        vector<Edge *> dad;
        vector<int> Q;

        Dinic(int N) : N(N), G(N), dad(N), Q(N) {}

        void add_edge(int from, int to, int cap) {
                G[from].push_back(Edge(from, to, cap, 0, G[to].size()));
                if (from == to) G[from].back().index++;
                G[to].push_back(Edge(to, from, 0, 0, G[from].size() - 1));
        }

        long long blocking_flow(int s, int t) {
                fill(dad.begin(), dad.end(), (Edge *) NULL);
                dad[s] = &G[0][0] - 1;

                int head = 0, tail = 0;
                Q[tail++] = s;
                while (head < tail) {
                        int x = Q[head++];
                        for (int i = 0; i < G[x].size(); i++) {
                                Edge &e = G[x][i];
                                if (!dad[e.to] && e.cap - e.flow > 0) {
                                        dad[e.to] = &G[x][i];
                                        Q[tail++] = e.to;
                                }
                        }
                }
                if (!dad[t]) return 0;

                long long totflow = 0;
                for (int i = 0; i < G[t].size(); i++) {
                        Edge *start = &G[G[t][i].to][G[t][i].index];
                        int amt = INF;
                        for (Edge *e = start; amt && e != dad[s]; e = dad[e->from]) {
                                if (!e) {
                                        amt = 0;
                                        break;
                                }
                                amt = min(amt, e->cap - e->flow);
                        }
                        if (amt == 0) continue;
                        for (Edge *e = start; amt && e != dad[s]; e = dad[e->from]) {
                                e->flow += amt;
                                G[e->to][e->index].flow -= amt;
                        }
                        totflow += amt;
                }
                return totflow;
        }

        long long max_flow(int s, int t) {
                long long totflow = 0;
                while (long long flow = blocking_flow(s, t))
                        totflow += flow;
                return totflow;
        }

        void clear_flow() {
                for (int i = 0; i < N; ++i)
                        for (int j = 0; j < G[i].size(); ++j)
                                G[i][j].flow = 0;

        }
};

const int sz = 5e4 + 10;
int n, m;
vector < int > G[105];
int src, sink;
int tot_v;
vector < int > pr;
bitset < sz > fl;
int fac[sz];

void siv() {
        for( int i=4; i<sz; i+=2 ) fl[i] = 1;
        for( int i=3; i*i<sz; i+=2 ) {
                if( fl[i] ) continue;
                for( int j=i*i; j<sz; j+=i ) fl[j] = 1;
        }
        pr.push_back( 2 );
        for( int i=3; i<sz; i+=2 ) if( fl[i] == 0 ) pr.push_back( i );
}

void factorise( int i, int num ) {
        for( const int x: pr ) {
                while( num % x == 0 ) {
                        num /= x;
                        tot_v++;
                        G[i].push_back( tot_v );
                        fac[tot_v] = x;
                }
        }
        if( num > 1 ) {
                tot_v++;
                G[i].push_back( tot_v );
                fac[tot_v] = num;
        }
}

int main() {
#ifdef CLown1331
        freopen( "in.txt","r",stdin );
#endif /// CLown1331

        siv();

        while( cin >> n >> m ) {

                tot_v = 0;

                for( int i=0; i<n; i++ ) {
                        G[i].clear();
                        int x;
                        cin >> x;
                        factorise( i, x );
                }

                src = 0;

                sink = tot_v + 1;

                Dinic graph( sink + 1 );

                while( m-- ) {
                        int x, y;
                        cin >> x >> y;
                        --x, --y;
                        if( x & 1 ) swap( x, y );
                        for( const int& u: G[x] ) {
                                for( const int& v: G[y] ) {
                                        if( fac[u] == fac[v] ) graph.add_edge( u, v, 1 );
                                }
                        }
                }

                for( int i=0; i<n; i++ ) {
                        for( const int& u: G[i] ) graph.add_edge( i & 1 ? u : src, i & 1 ? sink : u, 1 );
                }

                cout << graph.max_flow( src, sink ) << "\n";

                cerr << "-----\n";
        }

        return 0;
}