#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int MAX = 1e5;
const int LIM = MAX + 15;
vector<int> prime; // tập các số nguyên tố từ 2 tới lim
vector<int> lpf; // lowest_prime_factor[x] trả về ước nguyên tố nhỏ nhất của x
vector<bool> is_prime;
int sieve(int lim = MAX)
{
if (lim <= 1) {
return 0;
}
prime.assign(1, 2);
lpf.assign(lim + 1, 2);
is_prime.assign(lim + 1, true);
lpf[1] = 1;
for (int i = 3; i <= lim; i += 2) {
if (is_prime[i]) {
prime.push_back(lpf[i] = i);
}
for (int j = 0; j < prime.size() && prime[j] <= lpf[i] && prime[j] * i <= lim; ++j) {
lpf[prime[j] * i] = prime[j];
is_prime[prime[j] * i] = false;
}
}
return prime.size();
}
int Mask(int x)
{
int mask = 1;
while (x > 1)
{
int p = lpf[x], f = 0; // p^f
do x /= p, ++f; while (p == lpf[x]);
const int r = f % 2;
if (r == 1) {
mask *= p;
}
}
return mask;
}
int cnt[LIM];
long long solve(int n)
{
memset(cnt, 0, sizeof(cnt[0]) * (n + 1));
sieve(n);
long long res = 0;
for (int x = 1; x <= n; ++x) {
res += cnt[Mask(x)]; // Ghép U với tất cả Y = V * Q^2 có Mask(X) = Mask(Y)
++cnt[Mask(x)]; // Tìm được thêm một giá trị X = U * P^2 với U = Mask(X)
}
return res;
}
int main()
{
for (int n = 1; n <= 100; ++n) {
cout << solve(n) << " ";
}
cout << endl;
return 0;
for (int n; cin >> n; ) {
cout << solve(n) << endl;
}
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8Y3N0cmluZz4KI2luY2x1ZGUgPHZlY3Rvcj4KCnVzaW5nIG5hbWVzcGFjZSBzdGQ7Cgpjb25zdCBpbnQgTUFYID0gMWU1Owpjb25zdCBpbnQgTElNID0gTUFYICsgMTU7Cgp2ZWN0b3I8aW50PiBwcmltZTsgLy8gdOG6rXAgY8OhYyBz4buRIG5ndXnDqm4gdOG7kSB04burIDIgdOG7m2kgbGltCnZlY3RvcjxpbnQ+IGxwZjsgLy8gbG93ZXN0X3ByaW1lX2ZhY3Rvclt4XSB0cuG6oyB24buBIMaw4bubYyBuZ3V5w6puIHThu5Egbmjhu48gbmjhuqV0IGPhu6dhIHgKdmVjdG9yPGJvb2w+IGlzX3ByaW1lOwppbnQgc2lldmUoaW50IGxpbSA9IE1BWCkKewogICAgaWYgKGxpbSA8PSAxKSB7CiAgICAgICAgcmV0dXJuIDA7CiAgICB9CiAgICBwcmltZS5hc3NpZ24oMSwgMik7CiAgICBscGYuYXNzaWduKGxpbSArIDEsIDIpOwogICAgaXNfcHJpbWUuYXNzaWduKGxpbSArIDEsIHRydWUpOwogICAgCiAgICBscGZbMV0gPSAxOwogICAgZm9yIChpbnQgaSA9IDM7IGkgPD0gbGltOyBpICs9IDIpIHsKICAgICAgICBpZiAoaXNfcHJpbWVbaV0pIHsKICAgICAgICAgICAgcHJpbWUucHVzaF9iYWNrKGxwZltpXSA9IGkpOwogICAgICAgIH0KICAgICAgICBmb3IgKGludCBqID0gMDsgaiA8IHByaW1lLnNpemUoKSAmJiBwcmltZVtqXSA8PSBscGZbaV0gJiYgcHJpbWVbal0gKiBpIDw9IGxpbTsgKytqKSB7CiAgICAgICAgICAgIGxwZltwcmltZVtqXSAqIGldID0gcHJpbWVbal07CiAgICAgICAgICAgIGlzX3ByaW1lW3ByaW1lW2pdICogaV0gPSBmYWxzZTsKICAgICAgICB9CiAgICB9CiAgICByZXR1cm4gcHJpbWUuc2l6ZSgpOwp9CgppbnQgTWFzayhpbnQgeCkKewogICAgaW50IG1hc2sgPSAxOwogICAgd2hpbGUgKHggPiAxKQogICAgewogICAgICAgIGludCBwID0gbHBmW3hdLCBmID0gMDsgLy8gcF5mCiAgICAgICAgZG8geCAvPSBwLCArK2Y7IHdoaWxlIChwID09IGxwZlt4XSk7CiAgICAgICAgY29uc3QgaW50IHIgPSBmICUgMjsKICAgICAgICBpZiAociA9PSAxKSB7CiAgICAgICAgICAgIG1hc2sgKj0gcDsKICAgICAgICB9CiAgICB9CiAgICByZXR1cm4gbWFzazsKfQoKaW50IGNudFtMSU1dOwpsb25nIGxvbmcgc29sdmUoaW50IG4pCnsKICAgIG1lbXNldChjbnQsIDAsIHNpemVvZihjbnRbMF0pICogKG4gKyAxKSk7CiAgICBzaWV2ZShuKTsKCiAgICBsb25nIGxvbmcgcmVzID0gMDsKICAgIGZvciAoaW50IHggPSAxOyB4IDw9IG47ICsreCkgewogICAgICAgIHJlcyArPSBjbnRbTWFzayh4KV07ICAgIC8vIEdow6lwIFUgduG7m2kgdOG6pXQgY+G6oyBZID0gViAqIFFeMiBjw7MgTWFzayhYKSA9IE1hc2soWSkKICAgICAgICArK2NudFtNYXNrKHgpXTsgICAgICAgICAvLyBUw6xtIMSRxrDhu6NjIHRow6ptIG3hu5l0IGdpw6EgdHLhu4sgWCA9IFUgKiBQXjIgduG7m2kgVSA9IE1hc2soWCkKICAgIH0KICAgIAogICAgcmV0dXJuIHJlczsKfQoKaW50IG1haW4oKQp7CiAgICBmb3IgKGludCBuID0gMTsgbiA8PSAxMDA7ICsrbikgewogICAgICAgIGNvdXQgPDwgc29sdmUobikgPDwgIiAiOwogICAgfQogICAgY291dCA8PCBlbmRsOwogICAgcmV0dXJuIDA7CiAgICAKICAgIGZvciAoaW50IG47IGNpbiA+PiBuOyApIHsKICAgICAgICBjb3V0IDw8IHNvbHZlKG4pIDw8IGVuZGw7ICAgIAogICAgfQogICAgcmV0dXJuIDA7Cn0=