「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;
}
posted @ 2019-10-25 13:22  15owzLy1  阅读(...)  评论(...编辑  收藏