zoukankan      html  css  js  c++  java
  • 杜教筛的学习笔记

    写这篇文章帮助自己回忆一下之前学习过的东西以及一些常见的反演套路吧(QWQ)

    首先简单介绍一下积性函数:

    (phi,mu,d...)这些都是积性函数

    定义是:若(f(x*y) = f(x)*f(y) quad (gcd(x,y)==1))

    (f(x))是一个积性函数。

    常见的积性函数:

    (mu,quadphi,quad d()因数个数函数()),因数个数和函数等......

    如果对于任意的(x,y)都有:(f(x*y)=f(x)*f(y))

    则称此函数为完全积性函数:

    常见有:

    (Id(x)= x, varepsilon(x) = (x==1), I(x) = 1)

    接下来是杜教筛的重头戏:

    迪利克雷卷积

    定义两个积性函数的迪利克雷卷积为:

    ((f*g)(x) = sum_{d|x}f(x)*g(dfrac{x}{d}))

    可以证明,(虽然我不会),两个积性函数的迪利克雷卷积得到的函数仍然是一个积性函数

    那么我们来考虑原来要求的东西

    比如要求(mu(x))的前缀和。

    那么我们可以考虑找一个函数和它卷起来。

    根据莫比乌斯函数的性质可以得到:(mu*I = varepsilon)

    当然还有一些用的比较多的:(下面会给出证明)

    证明.ing

    ((phi*I)(x) = Id(x))

    ((mu*Id)(x) = phi(x))

    简单证明一下:

    ((phi*I)(x) = Id(x))

    其实就是:

    (sum_{i|x} phi(i) * I(x/i)), 其中(I(x/i) = 1)

    也就是:

    (sum_{i|x}phi(i))

    我们可以考虑欧拉函数的实际意义,(phi(i))表示为(1-i)中与(i)互质的数的个数。

    那么我们不妨假设(n)的因子依次为:(1,p1,p2.......n(p_i)不一定为质数!())

    接着我们考虑对于(gcd(n, a) = 1), 其中,满足这个式子的(a)的个数就是(phi(n))

    考虑(gcd(n, a) = d)的时候,那么(d|n)(d|a),所以其实这个式子就是: (gcd(n/d, a/d) = 1) ,满足这个式子的(a)的个数为(:phi(n/d))个。

    不难发现:(sum_{i|x}phi(i) = sum_{i|x} phi(x/i)) 而这个式子的答案的意义为:与(x)(gcd)依次为(1,p_1...p_n)的数的个数,这个数的个数为(x)

    所以:(sum_{i|x}phi(i) = x = Id(x))

    接下来我们证明这个:

    ((mu*Id)(x) = phi(x))

    不难发现,卷积其实具有交换律。((f*g*h)(x) = (f*h*g)(x))

    所以:(mu*Id*I = mu*I*Id = phi*I)

    即:(mu*Id*I = phi* I),故:(mu*Id = phi)

    完毕撒花

    接下来我们回到题目,我们要求这两个东西:

    [sum_{i=1}^nmu(i) ]

    [sum_{i=1}^nphi(i) ]

    我们可以先找一个东西和这个函数卷起来。(以第一个前缀和为例)

    (mu*I = varepsilon)

    所以这两个东西卷在一起的前缀和即:

    [sum_{i=1}^nsum_{d|i}mu(d)*I(dfrac{i}{d}) ]

    稍微改写一下:

    [sum_{d=1}^nI(d)*sum_{k=1}^{frac{n}{k}}mu(k) ]

    然而实际上我们有:(mu*I=varepsilon)

    所以原来的式子就是:

    [sum_{i=1}^nvarepsilon(i) = 1 ]

    现在我们怎么根据这个式子得到莫比乌斯函数的前缀和呢?

    [sum_{i=1}^nmu(i) = sum_{d=1}^nI(d)*sum_{k=1}^{frac{n}{k}}mu(k) - sum_{d=2}^nI(d)*sum_{k=1}^{frac{n}{k}}mu(k) ]

    因为(d=2)以后的地方都会被抵消掉。

    我们可以再记(G(x) = sum_{i=1}^xmu(i))

    所以我们再把原式化简得到:

    (G(n) = 1()(sum_{i=1}varepsilon(i)) - sum_{d=2}^nI(d)*G(frac{n}{k}))

    后面那一坨可以整除分块(+)递归处理

    (sum_{i=1}^nphi(i))也可以类似处理。

    只不过要利用(phi*I = Id)的性质。

    当然还有一些其他的利用比如:((id*id = d))(id)函数卷上(id)函数即为(d)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int read() {
    	char cc = getchar(); int cn = 0, flus = 1;
    	while(cc < '0' || cc > '9') {  if( cc == '-' ) flus = -flus;  cc = getchar();  }
    	while(cc >= '0' && cc <= '9')  cn = cn * 10 + cc - '0', cc = getchar();
    	return cn * flus;
    }
    #define rep( i, s, t ) for( register int i = s; i <= t; ++ i )
    #define LL long long
    #define il inline
    const int N = 5000000 + 5;
    LL phi[N], f2[N];
    int u[N], f1[N], pr[N], top, maxn;
    bool isp[N];
    map< int, LL > map1, map2;
    il void init() {
    	f1[1] = f2[1] = u[1] = phi[1] = 1;
    	maxn = N - 5;
    	rep( i, 2, maxn ) {
    		if( !isp[i] ) pr[++ top] = i, u[i] = -1, phi[i] = i - 1;
    		rep( j, 1, top ) {
    			int p = pr[j];
    			if( p * i > maxn ) break;
    			isp[i * p] = 1;
    			if( i % p == 0 ) {  phi[p * i] = p * phi[i]; break; }
    			phi[i * p] = phi[i] * phi[p], u[i * p] = u[i] * u[p];
    		}
    		f1[i] = f1[i - 1] + u[i], f2[i] = f2[i - 1] + phi[i];
    	}
    } 
    il int solve1( int x ) { //mu
    	if( x <= maxn ) return f1[x];
    	if( map1[x] ) return map1[x];
    	int Id = 1, l, r;
    	for( l = 2; l <= x; l = r + 1 ) {
    		r = ( x / ( x / l ) );
    		Id -= ( r - l + 1 ) * solve1( x / l );
    	}
    	return map1[x] = Id;
    }
    il LL solve2( LL x ) {
    	if( x <= maxn ) return f2[x];
    	if( map2[x] ) return map2[x];
    	LL Id = ( 1ll * x * ( x + 1ll ) / 2ll );
    	int l, r;
    	for( l = 2; l <= x; l = r + 1 ) {
    		r = ( x / ( x / l ) );
    		Id -= 1ll * ( r - l + 1 ) * solve2( x / l );
    	}
    	return map2[x] = Id;
    }
    signed main()
    {
    	init(); int T = read(), x;
    	while( T -- ) {
    		x = read();
    		printf("%lld %d
    ", solve2(x), solve1(x) );
    	}
    	return 0;
    }
    

    注意(phi)函数的前缀和要开long long

  • 相关阅读:
    通过IDEA解决spring配置文件
    idea中xml打开方式变成file,改回来
    idea 搜索不到前端的ajax controller接口的原因
    IDEA 出现 updating indices 卡进度条问题的解决方案并加快索引速度
    java 循环中使用list时,出现list中全部加入了对象导致没有实现分组的解决方案
    java 从字符串中 以单个或多个空格进行分隔 提取字符串
    idea ssm项目出现日志中文乱码,封装的json中的msg字段中文乱码(但是json封装的bean中的字段不乱码)等其他各种项目下的中文乱码解决方案
    javaweb 解决jsp中${}传递中文值到后端以及get请求中文乱码的问题
    idea 开发javaee 时,出现访问的文件和源文件不一样,没有正常更新的解决方案
    java 迭代器只遍历了一次的解决方案
  • 原文地址:https://www.cnblogs.com/Soulist/p/10596828.html
Copyright © 2011-2022 走看看