zoukankan      html  css  js  c++  java
  • 莫比乌斯反演学习笔记

    前言

    本文只是作者学习莫比乌斯反演后做的相关笔记,可能并不适合入门。

    基础

    莫比乌斯函数

    (x=p_1^{alpha_1} imes p_2^{alpha_2} imes dots imes p_k^{alpha_k})

    则:

    (mu(x)=egin{cases} 1&{x=1} \ 0&{alpha_i>1(1le ile k)} \ (-1)^k & ext{otherwise} end{cases})

    一个基本性质

    (S(n)=sumlimits_{d|n}mu(d))

    (S(n)=[n=1])

    证明略。

    一个简单结论

    [[gcd(i,j)=1]Leftrightarrowsumlimits_{d|gcd(i,j)}mu(d) ]

    第一个式子

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

    证明:

    [egin{aligned} f(n) &= sumlimits_{d|n}mu(d)F(frac{n}{d}) \ &= sumlimits_{d|n}mu(d)sumlimits_{i|frac{n}{d}}f(i) \ &= sumlimits_{i|n}f(i)sumlimits_{d|frac{n}{i}}mu(d) \ &= sumlimits_{i|n}f(i)S(frac{n}{i}) \ &= f(n) &&square end{aligned}]

    第二个式子

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

    证明:

    (d'=frac{d}{n})

    [egin{aligned} f(n) &= sumlimits_{n|d}mu(frac{d}{n})F(d) \ &= sumlimits_{n|d}mu(frac{d}{n})sumlimits_{d|i}f(i) \ &= sumlimits_{n|i}f(i)sumlimits_{d'|frac{n}{i}}mu(d') \ &= sumlimits_{n|i}f(i)S(frac{n}{i}) \ &= f(n) &&square end{aligned}]

    值得注意的是,我们在做题中常用的是第二个式子。

    例题

    [HAOI2011]Problem b

    题意:求 (sumlimits_{ale xle b}sumlimits_{cle yle d}[gcd(x, y)=k])

    (S(a, b)=sumlimits_{1le xle a}sumlimits_{1le yle b}[gcd(x, y)=k])

    可以通过二维前缀和的方式转化问题,答案即为 (S(b,d)-S(a-1,d)-S(b,c-1)+S(a-1,c-1))

    接下来有两种方法求解。

    方法一:

    (n=lfloorfrac{a}{k} floor)(m=lfloorfrac{b}{k} floor)

    [egin{aligned} &sumlimits_{x=1}^asumlimits_{y=1}^b [gcd(x,y)=k] \ =&sumlimits_{x=1}^{n}sumlimits_{y=1}^{m}[gcd(x,y)=1] \ =&sumlimits_{x=1}^{n}sumlimits_{y=1}^{m}sumlimits_{d|gcd(x,y)}mu(d) \ =&sumlimits_{x=1}^nsumlimits_{y=1}^msumlimits_{d|x,d|y}mu(d) \ =&sumlimits_{d=1}^{min(n,m)}mu(d)sumlimits_{lfloorfrac{n}{d} floor}sumlimits_{lfloorfrac{m}{d} floor}1 \ =&sumlimits_{d=1}^{min(n,m)}mu(d)lfloorfrac{n}{d} floorlfloorfrac{m}{d} floor end{aligned}]

    方法二:

    (F(n)=sumlimits_{x=1}^asumlimits_{y=1}^b[n|gcd(x,y)]=lfloorfrac{a}{n} floorlfloorfrac{b}{n} floor)(f(n)=sumlimits_{x=1}^asumlimits_{y=1}^b[gcd(x,y)=n])

    很显然有:(F(n)=sumlimits_{n|d}f(d))

    莫比乌斯反演得到:(f(n)=sumlimits_{n|d}mu(frac{d}{n})F(d))

    (d'=frac{d}{n})(a'=frac{a}{n})(b'=frac{b}{n})

    推式子:

    [egin{aligned} f(n)&=sumlimits_{n|d}mu(frac{d}{n})F(d) \ &=sumlimits_{n|d}mu(frac{d}{n})lfloorfrac{a}{n} floorlfloorfrac{b}{n} floor \ &=sumlimits_{d'}mu(d')lfloorfrac{a}{d'n} floorlfloorfrac{b}{d'n} floor \ &=sumlimits_{d'}mu(d')lfloorfrac{a'}{d'} floorlfloorfrac{b'}{d'} floor \ end{aligned}]

    然后整除分块即可。

    代码:

    #include <bits/stdc++.h>
    #define DEBUG fprintf(stderr, "Passing [%s] line %d
    ", __FUNCTION__, __LINE__)
    #define File(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)
    
    using namespace std;
    
    typedef long long LL;
    typedef pair <int, int> PII;
    typedef pair <int, PII> PIII;
    
    template <typename T>
    inline T gi()
    {
        T f = 1, x = 0; char c = getchar();
        while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
        while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return f * x;
    }
    
    const int INF = 0x3f3f3f3f, N = 50003, M = N << 1;
    
    int T;
    int mu[N], sum[N];
    bool isprime[N];
    int pri[N], tot;
    
    inline void pre()
    {
    	mu[1] = 1;
    	for (int i = 2; i <= 50000; i+=1)
    	{
    		if (!isprime[i]) pri[++tot] = i, mu[i] = -1;
    		for (int j = 1; j <= tot && 1ll * i * pri[j] <= 50000; j+=1)
    		{
    			isprime[i * pri[j]] = true;
    			if (i % pri[j] == 0) break;
    			mu[i * pri[j]] = -mu[i];
    		}
    	}
    	for (int i = 1; i <= 50000; i+=1) sum[i] = sum[i - 1] + mu[i];
    }
    
    inline LL S(int a, int b, int k)
    {
    	a /= k, b /= k;
    	int n = min(a, b);
    	LL ans = 0;
    	for (int l = 1, r; l <= n; l = r + 1)
    	{
    		r = min(n, min(a / (a / l), b / (b / l)));
    		ans = ans + 1ll * (sum[r] - sum[l - 1]) * (a / l) * (b / l);
    	}
    	return ans;
    }
    
    int main()
    {
        //File("");
        pre();
        T = gi <int> ();
        while (T--)
        {
        	int a = gi <int> (), b = gi <int> (), 
        		c = gi <int> (), d = gi <int> (), 
        		k = gi <int> ();
        	printf("%lld
    ", S(b, d, k) - S(a - 1, d, k) 
        					- S(b, c - 1, k) + S(a - 1, c - 1, k));
        }
        return 0;
    }
    
  • 相关阅读:
    DLL相关
    设备实时监控
    VC++定时器的运用
    iOS开发多线程篇—GCD的常见用法
    iOS开发多线程篇—线程的状态
    iOS开发多线程篇—GCD介绍
    iOS开发多线程篇—线程间的通信
    iOS开发多线程篇—线程安全
    iOS开发多线程篇—创建线程
    iOS开发多线程篇—多线程简单介绍
  • 原文地址:https://www.cnblogs.com/xsl19/p/14197647.html
Copyright © 2011-2022 走看看