// Slower C++ solution:
#include <bits/stdc++.h>



using namespace std;



typedef long long ll;

typedef unsigned long long ull;

typedef long double ld;

typedef pair<ll, ll> P;



#define EACH(i,a) for (auto& i : a)

#define FOR(i,a,b) for (ll i=(a);i<(b);i++)

#define RFOR(i,a,b) for (ll i=(b)-1;i>=(a);i--)

#define REP(i,n) for (ll i=0;i<(n);i++)

#define RREP(i,n) for (ll i=(n)-1;i>=0;i--)

#define debug(x) cout<<#x<<": "<<x<<endl

#define pb push_back

#define ALL(a) (a).begin(),(a).end()



const ll linf = 1e18;

const int inf = 1e9;

const double eps = 1e-12;

const double pi = acos(-1);



template<typename T>

istream& operator>>(istream& is, vector<T>& vec) {

    EACH(x,vec) is >> x;

    return is;

}

template<typename T>

ostream& operator<<(ostream& os, vector<T>& vec) {

    REP(i,vec.size()) {

        if (i) os << " ";

        os << vec[i];

    }

    return os;

}

template<typename T>

ostream& operator<<(ostream& os, vector< vector<T> >& vec) {

    REP(i,vec.size()) {

        if (i) os << endl;

        os << vec[i];

    }

    return os;

}

struct Edge {

    ll to, cap, rev;

};



vector< vector<Edge> > G;



void add_edge(ll from, ll to, ll cap) {

    G[from].pb({to, cap, (ll)G[to].size()});

    G[to].pb({from, 0, (ll)G[from].size()-1});

}



ll dfs(ll v, ll t, ll f, vector<bool>& used) {

    if (v == t) return f;

    if (used[v]) return 0;

    used[v] = true;

    EACH(e, G[v]) {

        if (e.cap > 0) {

            ll d = dfs(e.to, t, min(f, e.cap), used);

            if (d > 0) {

                e.cap -= d;

                G[e.to][e.rev].cap += d;

                return d;

            }

        }

    }

    return 0;

}



ll max_flow(ll s, ll t) {

    ll res = 0;

    while (1) {

        vector<bool> used(G.size(), false);

        ll f = dfs(s, t, inf, used);

        if (f == 0) break;

        res += f;

    }

    return res;

}



int gcd(int a, int b) {

    if (b == 0) return a;

    return gcd(b, a%b);

}



int main() {

    std::ios::sync_with_stdio(false);

    std::cin.tie(0);

    int m, n;

    while (cin >> m >> n, m || n) {

        vector<int> b(m), r(n); cin >> b >> r;

        vector<int> bid(m), rid(n);

        REP(i, m) bid[i] = i;

        REP(i, n) rid[i] = m+i;

        int s = m+n, t = s+1;

        G.clear();

        G.resize(t+1);

        REP(i, m) REP(j, n) {

            if ( gcd(b[i], r[j]) > 1 ) {

                add_edge(bid[i], rid[j], 1);

            }

        }

        REP(i, m) add_edge(s, bid[i], 1);

        REP(i, n) add_edge(rid[i], t, 1);

        cout << max_flow(s, t) << endl;

    }

}

// Faster C++ solution for the same problem (measured speedup: 1.102928030090308x):
#include <bits/stdc++.h>



using namespace std;



typedef long long ll;

typedef unsigned long long ull;

typedef long double ld;

typedef pair<ll, ll> P;



#define EACH(i,a) for (auto& i : a)

#define FOR(i,a,b) for (ll i=(a);i<(b);i++)

#define RFOR(i,a,b) for (ll i=(b)-1;i>=(a);i--)

#define REP(i,n) for (ll i=0;i<(n);i++)

#define RREP(i,n) for (ll i=(n)-1;i>=0;i--)

#define debug(x) cout<<#x<<": "<<x<<endl

#define pb push_back

#define ALL(a) (a).begin(),(a).end()



const ll linf = 1e18;

const int inf = 1e9;

const double eps = 1e-12;

const double pi = acos(-1);



template<typename T>

istream& operator>>(istream& is, vector<T>& vec) {

    EACH(x,vec) is >> x;

    return is;

}

template<typename T>

ostream& operator<<(ostream& os, vector<T>& vec) {

    REP(i,vec.size()) {

        if (i) os << " ";

        os << vec[i];

    }

    return os;

}

template<typename T>

ostream& operator<<(ostream& os, vector< vector<T> >& vec) {

    REP(i,vec.size()) {

        if (i) os << endl;

        os << vec[i];

    }

    return os;

}

class MaxFlow {

    struct Edge {

        ll to, cap, rev;

    };

    ll V;

    vector<vector<Edge>> G;

    vector<ll> bfs(ll s) {

        vector<ll> dist(V, linf);

        dist[s] = 0;

        queue<ll> Q; Q.push(s);

        while ( !Q.empty() ) {

            ll v = Q.front(); Q.pop();

            EACH(e, G[v]) {

                if (e.cap > 0 && dist[e.to] == linf) {

                    dist[e.to] = dist[v]+1;

                    Q.push(e.to);

                }

            }

        }

        return dist;

    }

    ll dfs(ll v, ll t, ll f, const vector<ll>& dist) {

        if (v == t) return f;

        EACH(e, G[v]) {

            if (e.cap > 0 && dist[e.to] == dist[v]+1) {

                ll d = dfs(e.to, t, min(f, e.cap), dist);

                if (d > 0) {

                    e.cap -= d;

                    G[e.to][e.rev].cap += d;

                    return d;

                }

            }

        }

        return 0;

    }

public:

    const vector<vector<Edge>> Graph() {

        return G;

    }

    MaxFlow(ll V) : V(V), G(V) {}

    void init(ll n) {

        V = n;

        G.assign(V, vector<Edge>());

    }

    void add(ll from, ll to, ll cap) {

        assert(V > 0);

        G[from].pb({to, cap, (ll)G[to].size()});

        G[to].pb({from, 0, (ll)G[from].size()-1});

    }

    ll flow(ll s, ll t, ll f=linf) {

        ll res = 0;

        while (1) {

            vector<ll> dist = bfs(s);

            if (dist[t] == linf) break;

            while (1) {

                ll df = dfs(s, t, f, dist);

                if (df == 0) break;

                f -= df;

                res += df;

            }

        }

        return res;

    }

};

ll gcd(ll a, ll b) {

    return b == 0 ? a : gcd(b, a%b);

}

int main() {

    std::ios::sync_with_stdio(false);

    std::cin.tie(0);

    ll m, n;

    while (cin >> m >> n, m || n) {

        vector<ll> A(m), B(n); cin >> A >> B;

        ll s = m+n, t = s+1;

        MaxFlow mf(t+1);

        REP(i, m) REP(j, n) {

            if (gcd(A[i], B[j]) > 1) {

                mf.add(i, m+j, 1);

            }

        }

        REP(i, m) mf.add(s, i, 1);

        REP(i, n) mf.add(m+i, t, 1);

        cout << mf.flow(s, t) << endl;

    }

}