#include #include #include #include #include #include #include #define rep(i, n) for(i = 0; i < n; i++) #define int long long using namespace std; mt19937_64 mt(23490832); vector generate(int L, int N) { vector p2, p3; p2.push_back(1); while (*p2.rbegin() <= L) p2.push_back(*p2.rbegin() * 2); p3.push_back(1); while (*p3.rbegin() <= L) p3.push_back(*p3.rbegin() * 3); vector s; for (int i = 0; p2[i] <= L; i++) { for (int j = 0; p2[i] * p3[j] <= L; j++) { s.push_back(p2[i] * p3[j]); } } sort(s.begin(), s.end()); vector used(s.size(), false); vector a; for (int i = 0; i < N; i++) { int r; do { r = mt() % s.size(); } while (used[r]); used[r] = true; a.push_back(s[r]); } sort(a.begin(), a.end()); return a; } vector generateSmallest(int L, int N) { vector p2, p3; p2.push_back(1); while (*p2.rbegin() <= L) p2.push_back(*p2.rbegin() * 2); p3.push_back(1); while (*p3.rbegin() <= L) p3.push_back(*p3.rbegin() * 3); vector s; for (int i = 0; p2[i] <= L; i++) { for (int j = 0; p2[i] * p3[j] <= L; j++) { s.push_back(p2[i] * p3[j]); } } sort(s.begin(), s.end()); s.resize(N); return s; } int subtask1(int L, int N, vector a) { int i, j; vector isOmote(L + 1, false); rep(i, N) isOmote[a[i]] = true; int ret = 0; for (i = 1; i <= L; i++) { if (isOmote[i]) { ret++; for (j = 2 * i; j <= L; j += i) isOmote[j] = !isOmote[j]; } } return ret; } pair, vector> setPrimeMebius(int n) { vector isPrime(n + 1, true); vector mebius(n + 1, 1); isPrime[0] = isPrime[1] = false; for (int i = 2; i <= n; i++) { if (isPrime[i]) { mebius[i] *= -1; int cnt = 2; if (i == 2) cnt = 0; for (int j = 2 * i; j <= n; j += i) { isPrime[j] = false; if (cnt == 0) { mebius[j] = 0; } else { mebius[j] *= -1; } cnt++; if (cnt == i) cnt = 0; } } } return pair, vector>(isPrime, mebius); } int gcd(int a, int b) { if (b == 0) return a; return gcd(b, a % b); } //subtask2_1, subtask2_2は、Σ|mebius(i)| (1≦i≦L) を返す. これはL=1,N=1,A={1}のときの答え。 //subtask2_1: 約数包除 O(√Llog√L), subtask2_2: メビウス関数を使った計算 O(√L) int subtask2_1(int L) { //sqL = floor(√L) int i, j; int sqL; for (sqL = 1; sqL * sqL <= L; sqL++); sqL--; vector cnts(sqL + 1); //cnts[m]: L以下のm^2の正の倍数であって、x>mについてx^2の倍数でないものの個数 for (i = sqL; i >= 1; i--) { cnts[i] = L / (i * i); for (j = 2 * i; j <= sqL; j += i) cnts[i] -= cnts[j]; } return cnts[1]; } int subtask2_2(int L, vector &mebius) { int ret = 0; for (int i = 1; i * i <= L; i++) { ret += mebius[i] * (L / (i * i)); } return ret; } int calc3_naive(int L, bool noDiv2, bool noDiv3) { int i, j; vector isOmote(L + 1, false); isOmote[1] = true; int ret = 0; for (i = 1; i <= L; i++) { if (isOmote[i]) { for (j = 2 * i; j <= L; j += i) isOmote[j] = !isOmote[j]; if (!((noDiv2 && i % 2 == 0) || (noDiv3 && i % 3 == 0))) ret++; } } return ret; } int loopCount = 0; int calc3_fast(int L, bool noDiv2, bool noDiv3, vector &mebius) { int ret = 0; for (int i = 1; i * i <= L; i++) { loopCount++; int keisu; if (i % 2 == 0 && noDiv2) keisu = 0; else if (i % 3 == 0 && noDiv3) keisu = 0; else { int c = L / (i * i); keisu = c; if (noDiv2) keisu -= c / 2; if (noDiv3) keisu -= c / 3; if (noDiv2 && noDiv3) keisu += c / 6; } ret += mebius[i] * keisu; } return ret; } string binaryStr(int x, int d) { string s; for (int i = d - 1; i >= 0; i--) s += ((x >> i) % 2) + '0'; return s; } int subtask3(int L, vector &a, vector &mebius) { int n = a.size(); vector div2(n), div3(n); int i, j; rep(i, n) { int t = a[i]; div2[i] = div3[i] = 0; while (t % 2 == 0) { t /= 2; div2[i]++; } while (t % 3 == 0) { t /= 3; div3[i]++; } } int ret = 0; rep(i, (1 << n)) { int l2 = -1, r2 = 1e+6, l3 = -1, r3 = 1e+6; //2^[l2, r2] * 3^[l3, r3] * 5^[0, 1] * 7 * [0, 1] * .... の形が表 int bitCount = 0; rep(j, n) { if ((i >> j) % 2) { l2 = max(l2, div2[j]); r2 = min(r2, div2[j] + 1); l3 = max(l3, div3[j]); r3 = min(r3, div3[j] + 1); bitCount++; } } if (bitCount == 0 || l2 > r2 || l3 > r3) continue; int tmpL = L; rep(j, l2) tmpL /= 2; rep(j, l3) tmpL /= 3; if (tmpL == 0) continue; bool noDiv2 = (l2 == r2); bool noDiv3 = (l3 == r3); int res = calc3_fast(tmpL, noDiv2, noDiv3, mebius); //cerr << "[subtask3] i: " << binaryStr(i, n) << ", l2: " << l2 << ", r2: " << r2 << ", l3: " << l3 << ", r3: " << r3 << ", tmpL: " << tmpL << ", res: " << res << endl; if (bitCount % 2 == 1) ret += res * (1LL << (bitCount - 1)); else ret -= res * (1LL << (bitCount - 1)); } return ret; } int subtask4(int L, vector &a, vector &mebius) { int n = a.size(); bool plot[60][60] = {false}; int i, j; rep(i, n) { int c2 = 0, c3 = 0, t = a[i]; while (t % 2 == 0) { t /= 2; c2++; } while (t % 3 == 0) { t /= 3; c3++; } plot[c2][c3] = true; } vector p2, p3; p2.push_back(1); p3.push_back(1); while (*p2.rbegin() <= L) p2.push_back(*p2.rbegin() * 2); while (*p3.rbegin() <= L) p3.push_back(*p3.rbegin() * 3); typedef tuple T; map mp; int ret = 0; for (i = 0; p2[i] <= L; i++) { for (j = 0; p2[i] * p3[j] <= L; j++) { //選ぶ要素のlcmが2^i * 3^jになる場合について数える int tmpL = L / (p2[i] * p3[j]); for (int k = 0; k < 16; k++) { int l; int max2 = -1, min2 = 1e+6, max3 = -1, min3 = 1e+6, cnt = 0; rep(l, 4) { if ((k >> l) & 1) { int c2 = i - l / 2; int c3 = j - l % 2; if (c2 < 0 || c3 < 0 || plot[c2][c3] == false) break; max2 = max(max2, c2); min2 = min(min2, c2); max3 = max(max3, c3); min3 = min(min3, c3); cnt++; } } if (l < 4 || cnt == 0 || max2 != i || max3 != j) continue; bool noDiv2 = (min2 != max2); bool noDiv3 = (min3 != max3); T key = T(tmpL, noDiv2, noDiv3); if (mp.find(key) == mp.end()) { mp[key] = calc3_fast(tmpL, noDiv2, noDiv3, mebius); } int res = mp[key]; if (cnt % 2 == 1) { ret += res * p2[cnt - 1]; } else { ret -= res * p2[cnt - 1]; } } } } return ret; } void spec_calc3(int maxL) { int sqL; for (sqL = 1; sqL * sqL <= maxL; sqL++); sqL--; auto prime_mebius = setPrimeMebius(sqL); vector mebius = prime_mebius.second; for (int L = 1; L <= maxL; L++) { for (int noDiv2 = 0; noDiv2 <= 1; noDiv2++) { for (int noDiv3 = 0; noDiv3 <= 1; noDiv3++) { int res1 = calc3_naive(L, noDiv2 == 1, noDiv3 == 1); int res2 = calc3_fast(L, noDiv2 == 1, noDiv3 == 1, mebius); if (res1 != res2) { cout << "[WA] L: " << L << ", noDiv2: " << noDiv2 << ", noDiv3: " << noDiv3 << endl; cout << "naive: " << res1 << ", ret: " << res2 << endl; return; } } } } cout << "Correct" << endl; } void spec_main() { int L; cin >> L; int N; cin >> N; int sqL; for (sqL = 1; sqL * sqL <= L; sqL++); sqL--; auto prime_mebius = setPrimeMebius(sqL); vector mebius = prime_mebius.second; for (int t = 0; t < 100; t++) { vector a = generate(L, N); int res1 = subtask1(L, N, a); int res2 = subtask4(L, a, mebius); if (res1 != res2) { cout << "WA[" << t << "] L: " << L << ", N: " << N << endl; for (int i = 0; i < a.size(); i++) cout << a[i] << " "; cout << endl; cout << "naive: " << res1 << ", ans: " << res2 << endl; subtask4(L, a, mebius); //デバッグする return; } } cout << "Correct" << endl; } void spec_speed() { int L; cin >> L; int N; cin >> N; vector a = generateSmallest(L, N); int i; rep(i, a.size()) cout << a[i] << " "; cout << endl; clock_t start = clock(); int sqL; for (sqL = 1; sqL * sqL <= L; sqL++); sqL--; auto prime_mebius = setPrimeMebius(sqL); vector mebius = prime_mebius.second; int res = subtask4(L, a, mebius); cout << (clock() - start) / (double)CLOCKS_PER_SEC << "[sec]" << endl; cout << res << endl; cout << "loopCount: " << loopCount << endl; } //想定解法 void run_solver() { int L, N; cin >> L >> N; vector a; int i; rep(i, N) { int x; cin >> x; a.push_back(x); } assert(L <= 1000000000000); assert(N <= 534); rep(i, N - 1) { assert(a[i] < a[i + 1]); } int sqL = 1; while (sqL * sqL <= L) sqL++; sqL--; auto prime_mebius = setPrimeMebius(sqL); vector mebius = prime_mebius.second; int res = subtask4(L, a, mebius); cout << res << endl; } signed main() { run_solver(); return 0; }