#include using namespace std; const int MAX = (int) 1e5 + 15; const int MAXOP = (int) 3e5; const int mod = (int) 1e9 + 7; int n, m, a[MAX], b[MAX], MAGIC; int prime[MAX]; vector > bucketQueries[MAX]; vector primeFactors[MAX]; long long modpow(long long a, long long b, long long mod) { long long res = 1; while (b) { if (b & 1) { res = (res * a) % mod; } a = (a * a) % mod; b >>= 1; } return res; } int operations[MAXOP], cnt[MAX]; int primeCnt; vector > queries; struct Data { int sz; int answer; Data() { answer = 0; sz = 0; for (int i = 0; i < primeCnt; i++) { cnt[i] = 0; } } void add(int x) { operations[sz++] = x; for (int i = 0; i < primeFactors[x].size(); i++) { int id = primeFactors[x][i]; answer += 2 * cnt[id] + 1; if (answer >= mod) { answer -= mod; } cnt[id]++; } } void roll_back() { assert(sz > 0); int x = operations[sz - 1]; sz--; for (int i = 0; i < primeFactors[x].size(); i++) { int id = primeFactors[x][i]; answer -= (2 * cnt[id] - 1); if (answer < 0) { answer += mod; } cnt[id]--; } } void clear() { int temp_sz = sz; for (int i = 0; i < temp_sz; i++) { roll_back(); } } }; int decideMagic() { int Q = queries.size(); int bestMagic = 0; long long minIterations = (long long) 1e18; for (int magic = 1; magic <= n; magic++) { long long iterations = 16L * (magic * (long long) Q + n * (long long) n / (long long) magic); if (iterations < minIterations) { minIterations = iterations; bestMagic = magic; } } cout << minIterations << endl; return bestMagic; } vector doIt() { //MAGIC = decideMagic(); MAGIC = sqrt(n); //cout << MAGIC << endl; for (int i = 0; i < queries.size(); i++) { bucketQueries[queries[i].first / MAGIC].push_back(make_pair(queries[i].second, i)); } int cntBuckets = (n + MAGIC - 1) / MAGIC; for (int i = 0; i < cntBuckets; i++) { sort(bucketQueries[i].begin(), bucketQueries[i].end()); } vector answer(queries.size()); Data data; for (int i = 0; i < queries.size(); i++) { int L = queries[i].first; int R = queries[i].second; if (L / MAGIC == R / MAGIC) { for (int j = L; j <= R; j++) { data.add(a[j]); } answer[i] = data.answer; data.clear(); } } for (int it = 0; it < cntBuckets; it++) { int cur = (it + 1) * MAGIC - 1; for (int idx = 0; idx < bucketQueries[it].size(); idx++) { int id = bucketQueries[it][idx].second; int L = queries[id].first; int R = queries[id].second; if (L / MAGIC != R / MAGIC) { for (int i = cur + 1; i <= R; i++) { data.add(a[i]); } cur = R; for (int i = L; i < min((it + 1) * MAGIC, n); i++) { data.add(a[i]); } answer[id] = data.answer; for (int i = L; i < min((it + 1) * MAGIC, n); i++) { data.roll_back(); } } } data.clear(); } return answer; } void solve() { for (int i = 0; i < m; i++) { for (int j = 0; j < m; j++) { int L = (b[i] + b[j]) % n; int R = (b[i] - b[j] + n) % n; if (L > R) { swap(L, R); } queries.push_back(make_pair(L, R)); } } vector queryResults = doIt(); int cur = 0; int ans = 0; for (int i = 0; i < m; i++) { int temp = 1; for (int j = 0; j < m; j++) { int L = (b[i] + b[j]) % n; int R = (b[i] - b[j] + n) % n; if (L > R) { swap(L, R); } temp = (long long) temp * queryResults[cur] % mod; cur++; } ans += temp; if (ans >= mod) { ans -= mod; } } printf("%d\n", ans); } void read() { scanf("%d %d", &n, &m); assert(n >= 1 && n <= 100000); assert(m >= 1 && m <= 500); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); assert(a[i] >= 1 && a[i] <= 100000); } for (int i = 0; i < m; i++) { scanf("%d", &b[i]); assert(b[i] >= 0 && b[i] < n); } } void pre() { for (int i = 2; i < MAX; i++) { prime[i] = true; } for (int i = 2; i * i < MAX; i++) { if (prime[i]) { for (int j = i + i; j < MAX; j += i){ prime[j] = false; } } } int cur = 0; for (int i = 2; i < MAX; i++) { if (prime[i]) { for (int j = i; j < MAX; j += i) { primeFactors[j].push_back(cur); } cur++; } } primeCnt = cur; } int main() { int start_time = clock(); //freopen("0.in.txt", "r", stdin); pre(); int T = 1; while (T--) { read(); solve(); } cerr << (clock() - start_time) / (double) CLOCKS_PER_SEC << endl; return 0; }