• 莫比乌斯反演


    推荐教程

    tls
    peng-ym

    莫比乌斯反演常用的两种形式:

    [egin{aligned} &(1).F(n)=sum_{d|n}f(d)Rightarrow f(n)=sum_{d|n}mu(d)F(frac{n}{d})&\ &(2).F(n)=sum_{n|d}f(d)Rightarrow f(n)=sum_{n|d}mu(frac{d}{n})F(n)(最常用)&\ end{aligned} ]

    题目

    Visible Lattice Points

    题意

    在一个(n imes n)的坐标轴上,问你有多少个点可以被((0,0,0))看到。

    思路

    我们知道一个点((x,y,z))要想被((0,0,0))看到,那么((x,y,z))((0,0,0))的连线上就不能有其他点存在,因此这个题求得就是(sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}sumlimits_{j=1}^{n}[gcd(i,j,k)=1])
    我们首先定义:

    [egin{aligned} &f(d) ext{为}gcd(i,j,k)=d ext{的有序对的对数}&\ &F(d) ext{为}gcd(i,j,k) ext{为}d ext{和}d ext{的倍数的有序对的对数}& end{aligned} ]

    然后我们用公式((2))来反演:
    (F(n))的定义我们知道

    [egin{aligned} F(n)=sum_{n|d}f(d) end{aligned} ]

    反演得到

    [f(n)=sum_{n|d}mu(frac{d}{n})F(d) ]

    (f(1))代入所求式子可以得到

    [egin{aligned} ans&=sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}sumlimits_{j=1}^{n}[gcd(i,j,k)=1]&\ &=f(1)&\ &=sum_{i=1}^{n}mu(i)F(i)& end{aligned} ]

    但是需要注意一点,那就是点在某坐标平面和某坐标轴上的情况,因此其实最终答案应该是(sumlimits_{i=1}^{n}mu(i)((n/i)^3+3(n/i)^2)+3)
    由于这个题目的(Tleq50),因此我们可以用(O(n))来写,但是如果(T)大一点的化就需要使用整除分块来写,这里就只贴整除分块的代码了。

    代码实现如下

    
    #include <set>
    #include <map>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <cmath>
    #include <ctime>
    #include <bitset>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    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
    #define rson rt<<1|1
    #define lowbit(x) x&(-x)
    #define name2str(name) (#name)
    #define bug printf("*********
    ")
    #define debug(x) cout<<#x"=["<<x<<"]" <<endl
    #define FIN freopen("in","r",stdin)
    #define IO ios::sync_with_stdio(false),cin.tie(0)
    
    const double eps = 1e-8;
    const int mod = 1e9 + 7;
    const int maxn = 1e6 + 7;
    const double pi = acos(-1);
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3fLL;
    
    int t, n, cnt;
    int isp[maxn], v[maxn], mu[maxn];
    
    void init() {
        mu[1] = 1;
        for(int i = 2; i < maxn; ++i) {
            if(!v[i]) {
                v[i] = 1;
                isp[cnt++] = i;
                mu[i] = -1;
            }
            for(int j = 0; j < cnt; ++j) {
                if(isp[j] * i > maxn) break;
                v[i*isp[j]] = 1;
                if(i % isp[j] == 0) {
                    mu[i*isp[j]] = 0;
                    break;
                }
                mu[i*isp[j]] = -mu[i];
            }
        }
        for(int i = 2; i < maxn; ++i) mu[i] += mu[i-1];
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        FIN;
    #endif
        init();
        scanf("%d", &t);
        while(t--) {
            scanf("%d", &n);
            LL ans = 0;
            for(int l = 1, r; l <= n; l = r + 1) {
                r = min(n, n / (n / l));
                int x = n / l;
                LL sum = 1LL * x * x * x + 3LL * x * x + 3LL * x;
                ans += sum * (mu[r] - mu[l-1]);
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
    

    下面的代码基本上都和上面的差不多所以就不写代码啦~

    GCD

    答案为(sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)=k]=sumlimits_{i=1}^{lfloorfrac{n}{k} floor}sumlimits_{j=1}^{lfloorfrac{m}{k} floor}[gcd(i,j)=1])
    定义

    [egin{aligned} &f(d) ext{为}gcd(i,j)=d ext{的有序对的对数}&\ &F(d) ext{为}gcd(i,j)=d ext{和}d ext{的倍数的有序对的对数}& end{aligned} ]

    [egin{aligned} &F(n)=sum_{n|d}f(d)&\ Rightarrow&f(n)=sum_{n|d}mu(frac{d}{n})F(d)& end{aligned} ]

    所以最终答案为

    [sumlimits_{i=1}^{min(n,m)}mu(i)lfloorfrac{n}{i} floorlfloorfrac{m}{i} floor ]

    不过要记得去重哦~

    小D的Lemon

    [prod_{i=1}^{n}prod_{j=1}^{m}g(gcd(i,j)) ]

    其中

    [g(x)= egin{cases} &1&,x=1\ &sumlimits_{i=1}^{n}k_i&,x!=1& end{cases} ,x=prod_{i=1}^{n}p_i^{k_i} ]

    我们首先将(gcd(i,j))提出来,然后变成(prodlimits_{k=1}^{min(n,m)}g(k)^{prodlimits_{i=1}^{n}prodlimits_{j=1}^{m}[gcd(i,j)=k]}),通过反演我们可以得到

    [egin{aligned} &prodlimits_{k=1}^{min(n,m)}g(k)^{sumlimits_{i=1}^{frac{n}{k}}sumlimits_{j=1}^{frac{m}{k}}[gcd(i,j)=1]}&\ =&prodlimits_{k=1}^{min(n,m)}g(k)^{sumlimits_{k|d}mu(frac{d}{k})lfloorfrac{n}{kd} floorlfloorfrac{m}{kd} floor}&\ =&prod_{T=1}^{min(n,m)}prod_{t|T}g(t)^{mu(frac{T}{t})}& end{aligned} ]

    由于(T)比较大,因此(O(n))的复杂度是无法通过的,因此我们需要预处理出(prodlimits_{t|T}g(t)),然后就可以用整除分块处理即可,总复杂度为(O(nlog(n)+Tsqrt n))

    #include <set>
    #include <map>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <cmath>
    #include <ctime>
    #include <bitset>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    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
    #define rson rt<<1|1
    #define lowbit(x) x&(-x)
    #define name2str(name) (#name)
    #define bug printf("*********
    ")
    #define debug(x) cout<<#x"=["<<x<<"]" <<endl
    #define FIN freopen("in","r",stdin)
    #define IO ios::sync_with_stdio(false),cin.tie(0)
    
    const double eps = 1e-8;
    const int mod = 1e9 + 7;
    const int maxn = 3e5 + 6;
    const double pi = acos(-1);
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3fLL;
    
    int t, n, m, cnt;
    int isp[maxn], mu[maxn], v[maxn];
    LL g[maxn], f[maxn], inv[maxn], invv[maxn];
    
    LL qpow(LL x, LL n) {
        LL res = 1;
        while(n) {
            if(n & 1) res = res * x % mod;
            x = x * x % mod;
            n >>= 1;
        }
        return res;
    }
    
    void init() {
        mu[1] = g[1] = 1;
        for(int i = 2; i < maxn; ++i) {
            if(!v[i]) {
                g[i] = 1;
                mu[i]  = -1;
                isp[cnt++] = i;
            }
            for(int j = 0; j < cnt && i * isp[j] < maxn; ++j) {
                v[i*isp[j]] = 1;
                g[i*isp[j]] = g[i] + 1;
                mu[i*isp[j]] = -mu[i];
                if(i % isp[j] == 0) {
                    mu[i*isp[j]] = 0;
                    break;
                }
            }
        }
        for(int i = 1; i < maxn; ++i) {
            f[i] = 1;
            invv[i] = qpow(g[i], mod - 2);
        }
        for(int i = 2; i < maxn; ++i) {
            for(int j = i; j < maxn; j += i) {
                if(mu[j/i] == 1) f[j] = f[j] * g[i] % mod;
                else if(mu[j/i] == -1) f[j] = f[j] * invv[i] % mod;
            }
        }
        f[0] = inv[0] = inv[0] = inv[1] = 1;
        for(int i = 2; i < maxn; ++i) {
            f[i] = f[i] * f[i-1] % mod;
            inv[i] = qpow(f[i], mod - 2);
        }
    }
    
    int main() {
        init();
        scanf("%d", &t);
        while(t--) {
            scanf("%d%d", &n, &m);
            if(n > m) swap(n, m);
            LL ans = 1;
            for(int l = 1, r; l <= n; l = r + 1) {
                r = min(n / (n / l), m / (m / l));
                ans = ans * qpow(f[r] * inv[l-1] % mod, 1LL * (n / l) * (m / l) % (mod - 1)) % mod; 
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
    

    小清新数论

    [egin{aligned} &sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}mu(gcd(i,j))&\ =&sumlimits_{d=1}^{n}sumlimits_{i=1}^{frac{n}{d}}sumlimits_{j=1}^{frac{n}{d}}[gcd(i,j)=1]&\ =&sumlimits_{d=1}^{n}mu(d)(2sumlimits_{i=1}^{frac{n}{d}}phi(i)-1)& end{aligned} ]

    #include <set>
    #include <map>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <cmath>
    #include <ctime>
    #include <bitset>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    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
    #define rson rt<<1|1
    #define lowbit(x) x&(-x)
    #define name2str(name) (#name)
    #define bug printf("*********
    ")
    #define debug(x) cout<<#x"=["<<x<<"]" <<endl
    #define FIN freopen("in","r",stdin)
    #define IO ios::sync_with_stdio(false),cin.tie(0)
    
    const double eps = 1e-8;
    const int mod = 998244353;
    const int maxn = 1e7 + 7;
    const double pi = acos(-1);
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3fLL;
    
    int n, cnt;
    int v[maxn], isp[maxn], phi[maxn], mu[maxn];
    
    void init() {
        mu[1] = phi[1] = 1;
        for(int i = 2; i <= n; ++i) {
            if(!v[i]) {
                v[i] = 1;
                mu[i] = -1;
                phi[i] = i - 1;
                isp[cnt++] = i;
            }
            for(int j = 0; j < cnt; ++j) {
                if(isp[j] > n / i) break;
                v[isp[j]*i] = 1;
                mu[i*isp[j]] = -mu[i];
                if(i % isp[j] == 0) {
                    mu[i*isp[j]] = 0;
                    phi[i*isp[j]] = phi[i] * isp[j] % mod;
                    break;
                }
                phi[i*isp[j]] = phi[i] * (isp[j] - 1) % mod;
            }
        }
        for(int i = 2; i <= n; ++i) (phi[i] += phi[i-1]) %= mod;
    }
    
    int main() {
        scanf("%d", &n);
        init();
        LL ans = 0;
        for(int i = 1; i <= n; ++i) {
            ans = ((ans + mu[i] * ((2LL * phi[n/i] % mod + mod) % mod - 1 + mod)) % mod + mod) % mod;
        }
        printf("%lld
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    (转载)Linux进程基础
    C语言字符串
    DNS域名解析服务
    Linux-SSH远程管理
    Linux文件系统深入了解
    Linux进程和计划任务管理
    Linux账户与权限管理
    MySQL实现读写分离
    SQL数据库常用函数
    MySQL进阶查询(二)
  • 原文地址:https://www.cnblogs.com/Dillonh/p/11162479.html
Copyright © 2020-2023  润新知