「luogu2350」[HAOI2012] 外星人
「luogu2350」[HAOI2012] 外星人
\(Description\):
以质数次幂的形式给出一个整数 \(N \ ( N = \prod p_i ^ {c_i} , p_i \leq 10 ^ 5 c_i \leq 10 ^ 9)\),求进行几次 \(N = \varphi(N)\) 后可以变成 \(1\)。
\(Solution\):
\[\varphi(N) = N \prod \frac{p_i - 1}{p_i} \\ \tag{Euler Function}
\]
观察上式得出 \(N\) 会少一个因子 \(p_i\) ,同时多出 \(p_i - 1\) 的因子;
注意到对于质因子 \(p \ (p > 2)\),一定有\(2 | p - 1\),所以必然多出一个因子 \(2\),同时增加一些其他质因子;
故只需要计算整个过程中 \(2\) 的个数,线筛即可;
特判一开始是否有因子 \(2\),有的话答案要加 \(1\) (产生 \(2\) )。
\(Source\):
#include <cstdio>
#include <cstring>
#include <algorithm>
int in() {
int x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }
const int N = 1e5 + 5;
int n;
int pri[N], f[N], min_pri[N];
void prep() {
for (int i = 2; i < N; ++i) {
if (!min_pri[i]) {
min_pri[i] = i;
pri[++pri[0]] = i;
}
for (int j = 1, tmp; j <= pri[0] && i * pri[j] < N; ++j) {
tmp = i * pri[j];
min_pri[tmp] = pri[j];
if (!(i % pri[j]))
break;
}
}
f[2] = 1;
for (int i = 3; i < N; ++i)
if (min_pri[i] == i)
f[i] = f[i - 1];
else
f[i] = f[i / min_pri[i]] + f[min_pri[i]];
}
int main() {
//freopen("in", "r", stdin);
prep();
int T = in();
while (T--) {
unsigned long long res = 0;
n = in();
for (int i = 1, x; i <= n; ++i) {
x = in();
if (x == 2)
--res;
res += 1ull * f[x] * in();
}
printf("%llu\n", res + 1);
}
return 0;
}