#include <bits/stdc++.h> using namespace std; string ltrim(const string &); string rtrim(const string &); vector<string> split(const string &); // Initialize with std::iota(parent, parent+n+1, 0), std::fill(sz, sz+n+1, 1); const int N = 1e6+10; // Upper bound for n const int M = 1e9+7; int parent[N]; int sz[N]; int sieve[N]; int twos[N]; // Uses path compression int find(int x) {return parent[x] = (x == parent[x] ? x : find(parent[x]));} bool disjoint(int x, int y) {return find(x) != find(y);} void join(int x, int y) { if (!disjoint(x, y)) return; int newPar = find(x), newChild = find(y); sz[newPar] += sz[newChild]; parent[newChild] = newPar; } int dsuSize(int x) {return sz[find(x)];} // Complete the solve function below. int solve(vector<int> a) { int n = a.size(); std::iota(parent, parent+N, 0), std::fill(sz, sz+N, 1); for(int i = 0; i < n; ++i) { int cur = a[i]; set<int> p; while(cur != 1) { p.insert(sieve[cur]); cur /= sieve[cur]; } // cout << p.size() << endl; vector<int> vec(p.size()); int idx = 0; for(int x : p) { // cout << x << ' '; vec[idx++] = x; } // cout << endl; // cout << vec.size() << endl; for(int j = 0; j < (int)vec.size()-1; ++j) { // cout << j << ' ' << vec.size() << endl; // cout << vec[j] << ' '; join(vec[j], vec[j+1]); } } set<int> s; int ones = 0; for(int i = 0; i < n; ++i) { if(a[i] == 1) ++ones; else s.insert(find(sieve[a[i]])); } return (twos[s.size()+ones]-2+M) % M; } void precomp() { std::iota(sieve, sieve+N, 0); for(int i = 2; i < N; ++i) { if(sieve[i] == i) { for(int j = i; j < N; j += i) { sieve[j] = i; } } } twos[0] = 1; for(int i = 1; i < N; ++i) { twos[i] = (twos[i-1]*2) % M; } } int main() { ofstream fout(getenv("OUTPUT_PATH")); precomp(); string t_temp; getline(cin, t_temp); int t = stoi(ltrim(rtrim(t_temp))); for (int t_itr = 0; t_itr < t; t_itr++) { string a_count_temp; getline(cin, a_count_temp); int a_count = stoi(ltrim(rtrim(a_count_temp))); string a_temp_temp; getline(cin, a_temp_temp); vector<string> a_temp = split(rtrim(a_temp_temp)); vector<int> a(a_count); for (int i = 0; i < a_count; i++) { int a_item = stoi(a_temp[i]); a[i] = a_item; } int result = solve(a); fout << result << "\n"; } fout.close(); return 0; } string ltrim(const string &str) { string s(str); s.erase( s.begin(), find_if(s.begin(), s.end(), not1(ptr_fun<int, int>(isspace))) ); return s; } string rtrim(const string &str) { string s(str); s.erase( find_if(s.rbegin(), s.rend(), not1(ptr_fun<int, int>(isspace))).base(), s.end() ); return s; } vector<string> split(const string &str) { vector<string> tokens; string::size_type start = 0; string::size_type end = 0; while ((end = str.find(" ", start)) != string::npos) { tokens.push_back(str.substr(start, end - start)); start = end + 1; } tokens.push_back(str.substr(start)); return tokens; }