zoukankan      html  css  js  c++  java
  • 51nod 1594 Gcd and Phi(莫比乌斯反演)

    题目链接

    传送门

    思路

    如果这题是这样的:

    [F(n)=sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}phi(gcd(i,j)) ]

    那么我们可能会想到下面方法进行反演:

    [egin{aligned} F(n)=&sumlimits_{k=1}^{n}phi(k)sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}[gcd(i,j)=k]&\ =&sumlimits_{k=1}^{n}phi(k)sumlimits_{i=1}^{frac{n}{k}}sumlimits_{j=1}^{frac{n}{k}}[gcd(i,j)=1]&\ end{aligned} ]

    (f(n))(gcd(i,j)=n)的有序对的对数,(g(n))(gcd(i,j)=n ext{和}n)的倍数的有序对的对数,则

    [egin{aligned} &g(n)=sumlimits_{n|d}f(d)&\ ightarrow&f(n)=sumlimits_{n|d}mu(frac{d}{n})g(d)& end{aligned} ]

    然后将(f(1)=sumlimits_{i=1}^{n}mu(i)g(i))代入(F(n))得到(F(n)=sumlimits_{k=1}^{n}phi(k)sumlimits_{i=1}^{frac{n}{k}}mu(i)g(i)),然后先预处理(sumlimits_{i=1}^{frac{n}{k}}mu(i)g(i)),然后暴力枚举(k)或者数论分块求解答案就可以了,这里有几道类似的题目,有兴趣的可以做一下。

    但是这题却不是我们所希望的那种形式,那么该怎么办呢?我们发现(n)小于等于(2e6),那么我们可以记录一下每个数的(phi)是多少,然后记录一下每个(phi)出现的次数后就可以转换成上述题意了(这个思想昨天的(CCPC)网络赛1010也用到了,不过这题由于后面不会处理就没补了23333),假设(c_i)表示(phi=i)的个数,那么求解的式子就变成了

    [F(n)=sumlimits_{k=1}^{n}phi(k)sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}c_ic_j[gcd(i,j)=k] ]

    (f(n))(sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}c_ic_j[gcd(i,j)=n])(g(n))(为和的倍数sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}c_ic_j[gcd(i,j) ext{为}n ext{和}n ext{的倍数}]),则

    [egin{aligned} g(n)=&sumlimits_{n|i}sumlimits_{n|j}c_ic_j&\ =&sumlimits_{i=1}^{n}c_isumlimits_{j=1}^{n}c_J&\ =&(sumlimits_{i=1}^{n}c_i)^2&\ =&sumlimits_{n|d}f(d)& end{aligned} ]

    那么

    [f(n)=sumlimits_{n|d}mu(frac{d}{n})g(d) ]

    最后答案为

    [F(n)=sumlimits_{k=1}^{n}phi(k)f(k) ]

    然后暴力枚举(k)求解即可。

    代码

    #include <set>
    #include <map>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <cmath>
    #include <ctime>
    #include <bitset>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cassert>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <unordered_map>
    using namespace std;
    
    typedef long long LL;
    typedef pair<LL, LL> pLL;
    typedef pair<LL, int> pLi;
    typedef pair<int, LL> pil;;
    typedef pair<int, int> pii;
    typedef unsigned long long uLL;
    
    #define lson (rt<<1),L,mid
    #define rson (rt<<1|1),mid + 1,R
    #define lowbit(x) x&(-x)
    #define name2str(name) (#name)
    #define bug printf("*********
    ")
    #define debug(x) cout<<#x"=["<<x<<"]" <<endl
    #define FIN freopen("/home/dillonh/CLionProjects/Dillonh/in.txt","r",stdin)
    #define IO ios::sync_with_stdio(false),cin.tie(0)
    
    const double eps = 1e-8;
    const int mod = 1000000007;
    const int maxn = 2000000 + 2;
    const double pi = acos(-1);
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3fLL;
    
    bool v[maxn];
    int t, n, cnt;
    int F[maxn], c[maxn], phi[maxn], p[maxn], mu[maxn];
    
    void init() {
        phi[1] = mu[1] = 1;
        for(int i = 2; i < maxn; ++i) {
            if(!v[i]) {
                p[cnt++] = i;
                phi[i] = i - 1;
                mu[i] = -1;
            }
            for(int j = 0; j < cnt && i * p[j] < maxn; ++j) {
                v[i*p[j]] = 1;
                phi[i*p[j]] = phi[i] * (p[j] - 1);
                mu[i*p[j]] = -mu[i];
                if(i % p[j] == 0) {
                    mu[i*p[j]] = 0;
                    phi[i*p[j]] = phi[i] * p[j];
                    break;
                }
            }
        }
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        FIN;
        time_t s = clock();
    #endif
        init();
        scanf("%d", &t);
        while(t--) {
            scanf("%d", &n);
            for(int i = 1; i <= n; ++i) {
                ++c[phi[i]];
            }
            F[1] = c[1];
            for(int i = 2; i <= n; ++i) {
                F[1] += c[i];
                for(int j = 1; j <= n / i; ++j) {
                    F[i] += c[i*j];
                }
            }
            LL sum = 1LL * F[1] * F[1], ans = 0;
            for(int i = 2; i <= n; ++i) {
                sum += 1LL* F[i] * F[i] * mu[i];
                LL tmp = 0;
                for(int j = 1; j <= n / i; ++j) {
                    tmp += 1LL * F[i*j] * F[i*j] * mu[j];
                }
                ans += tmp * phi[i];
            }
            ans += sum;
            printf("%lld
    ", ans);
            for(int i = 1; i <= n; ++i) F[i] = c[i] = 0;
        }
    #ifndef ONLINE_JUDGE
        printf("It costs %.3fs
    ", 1.0 * (clock() - s) / CLOCKS_PER_SEC);
    #endif
        return 0;
    }
    
  • 相关阅读:
    【bzoj1010】[HNOI2008]玩具装箱toy
    bzoj 3173
    bzoj 1179
    bzoj 2427
    bzoj 1051
    bzoj 1877
    bzoj 1066
    bzoj 2127
    bzoj 1412
    bzoj 3438
  • 原文地址:https://www.cnblogs.com/Dillonh/p/11406296.html
Copyright © 2011-2022 走看看