會長編號 N,會員 1..N。與會長有公約數(>1)為老朋友,否則為新朋友。求新朋友數 = 1≤xφ(N)(歐拉函數)。
int find_divisors(int n, int d[]) {
int cnt = 0;
for (int i = 2; i <= n/2; i++)
if (n % i == 0) d[cnt++] = i;
return cnt;
}
int count_new_friends(int n, int d[], int len) {
bool sieve[33000] = {0};
for (int i = 0; i < len; i++) {
for (int j = d[i]; j < n; j += d[i])
sieve[j] = true; // 標記有公約數
}
int cnt = 0;
for (int i = 1; i < n; i++) if (!sieve[i]) cnt++;
return cnt;
}
分解 N = ∏ p_i^{k_i},φ(N) = N ∏ (1 - 1/p_i)。對多測試用例(CN<10000),預篩素數至 32768,每查詢 O(√N) 分解極快。
int phi(int n) {
int res = n;
for (int p = 2; p * p <= n; p++) {
if (n % p == 0) {
while (n % p == 0) n /= p;
res -= res / p;
}
}
if (n > 1) res -= res / n;
return res;
}
N≤32767 尚可但較慢。