关于在线性筛中求积性函数

蒟蒻以欧拉心算为例子,浅谈一下如何求一些较复杂的积性函数

欧拉心算:

\[\sum_{i=1}^n\sum_{j=1}^n\phi(gcd(i,j))\]

与之前的一样:

\[\sum_{d=1}^n\phi(d)\sum_{i=1}^{[n/d]}\sum_{j=1}^{[n/d]}[gcd(i,j)==1]\]

利用\(\mu\)函数的性质:

\[\sum_{d=1}^n\phi(d)\sum_{i=1}^{[n/d]}\sum_{j=1}^{[n/d]}\sum_{k|gcd(i,j)}\mu(k)\]

然后:

\[\sum_{d=1}^n\phi(d)\sum_{k=1}^{[n/d]}\mu(k)sum([n/kd])^2\]

其中\(sum(k)\)表示\(k*(k+1)/2\)

一般套路,设\(T=k*d\)

那么

\[\sum_{T=1}^n\sum_{d|T}\phi(d)*\mu(T/d)*sum([n/T])^2\]

于是我们现在的主要矛盾是要求出中间那一串。

有点像狄利克雷卷积

我们知道

\[F(T)=\sum_{d|T}\phi(d)*\mu(T/d)\]

这显然也是一个积性函数

我们主要的问题是如何用线性筛把它求出来,以维护一个前缀和

1.当\(T\)是质数的时候:

\[F(T)=\phi(T)*\mu(1)+\phi(1)*\mu(T)\]

于是:

\[F(T)=T-2\]

2.当\(T=a*b\)其中\(gcd(a,b)==1\)

那么

\[F(T)=F(a)*F(b)\]

3.于是主要矛盾便成了当\(gcd(a,b)!=1\)时的情况,那么我们这时依

然要求出\(T\),我们记\(low(x)\)表示为\(x\)分解出来后最小质因子的最

大次方的数,例如:\(low(36)=2^2\)

大家知道线性筛筛素数每次每个数都是被自己的最小质因子筛掉的。

刚好,设当前为\(a\),最小质因子为\(p\)

那么:

\[F(a*p)=F(a/low(a))*F(p*low(a))\]

但是有一一些特例:

\[F(8)=F(4/low(4))*low(2*low(4))=F(1)*F(8)\]

当某个数刚好是某个质数的某次方时,这样的数似乎不行。

所以,我们在筛积性函数时,可以用这样的方法筛出来的前提就是:

1.当\(T\)为质数的时候可以快速得出

2.当\(T\)为\(p^k\)(\(p\)是质数)时可以快速得出,那么我们就可以用线

性筛得出积性函数的值了。

而这道题,\(F(p^k)\)是很好求了

最后就是这个\(low\)值,在线性筛的时候可以求出了

蒟蒻贴代码:

#include<iostream>
#include<cstdio>
using namespace std;
#define N 10000000 + 5
int num = 0 , n , T ;
int book[N] , p[N] ;
long long sum[N] , low[N] , f[N] , phi[N] ;
void Init(int x){
    f[1] = 1 ;
    low[1] = 1 ;
    sum[1] = 1 ;
    for(int i = 2 ; i <= x ; i++ ){
        if( book[i] == 0 ) p[++num] = i , f[i] = i - 2 , low[i] = i , phi[i] = i - 1 ;
        for(int j = 1 ; j <= num && p[j] * i <= x ; j++ ){
            int v = i * p[j] ;
            book[ v ] = 1 ;
            if( ( i % p[j] ) != 0 ){
                f[ v ] = f[ i ] * f[ p[j] ] ;
                phi[ v ] = phi[ i ] * phi[p[j]] ;
                low[ v ] = p[j] ;
            }
            else{
                phi[ v ] = phi[ i ] * p[j] ;
                low[ v ] = low[i] * p[j] ;
                if( i == low[i] ) f[ v ] = phi[v] + phi[i] * ( -1 ) ;
                else f[ v ] = f[ i / low[i] ] * f[ p[j] * low[i] ] ;
                break ;
            }
        }
        sum[i] = sum[ i - 1 ] + f[i] ;
    }
    return ;
}
int main()
{
    scanf("%d" , &T ) ;
    Init(N - 3) ;
    while( T-- ){
        scanf("%d" , &n ) ;
        long long ans = 0 ;
        int l , r ;
        for(int l = 1 ; l <= n ; l = r + 1 ){
            r = n / ( n / l ) ;
            ans += 1ll*( sum[r] - sum[l-1] ) * ( n / l ) * ( n / l ) ;
        }
        printf("%lld\n" , ans ) ;
    }
}

原文地址:https://www.cnblogs.com/powerYao/p/11445315.html

时间: 2024-10-07 20:28:31

关于在线性筛中求积性函数的相关文章

线性筛与积性函数

线性筛 最初,线性筛只是用来筛质数罢了... void sieve(int n) { static int v[N], p[N], pr; // v[i] 表示 i 的最小质因子 // p[N] 和 pr 用来存质数表 for (int i = 2; i <= n; ++i) { if (v[i] == 0) v[i] = i, p[++pr] = i; // 没被筛,是质数 for (int j = 1; j <= pr && i*p[j] <= n; ++j) { v

读贾志鹏《线性筛法与积性函数》笔记

1.欧拉筛法在线性时间内求素数以及欧拉函数 代码: 1 procedure get; 2 var i,j,k:longint; 3 begin 4 tot:=0; 5 fillchar(check,sizeof(check),false); 6 for i:=2 to n do 7 begin 8 if not(check[i]) then 9 begin 10 inc(tot); 11 p[tot]:=i; 12 fai[i]:=i-1; 13 end; 14 for j:=1 to tot

欧拉线性筛 和 欧拉函数的求值

PS:求逆元的部分在文章最后...最好也看看前边的知识吧qwq 用筛法求素数的基本思想是:把从1开始的.某一范围内的正整数从小到大顺序排列, 1不是素数,首先把它筛掉.剩下的数中选择最小的数是素数,然后去掉它的倍数.依次类推,直到筛子为空时结束.(来自 百度百科) 一般的筛法(埃拉托斯特尼筛法)的效率是O(nlglgn),但出题人卡你可就凉了.. (就不介绍了(逃)) 下面我们来说O(n)的欧拉线性筛 埃筛之所以慢,是因为有些合数被重复筛除(如:6会被2和3重复筛) 但是欧拉筛保证 每一个数p,

数论 - 线性筛法与积性函数

首先以求1000000以内的素数为例来探讨筛法 Eratosthenes筛法(埃拉托斯特尼筛法) 时间复杂度:O(N*loglogN) 空间复杂度:O(N) 代码: #include <map> #include <set> #include <list> #include <cmath> #include <deque> #include <queue> #include <stack> #include <bit

P2158 [SDOI2008]仪仗队 线性筛(欧拉函数和素数表)

上三角行恰好是[1,n-1]的欧拉函数 http://www.luogu.org/problem/show?pid=2158#sub 1 //#pragma comment(linker, "/STACK:167772160") 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <iostream> 6 #include <queue&g

积性函数筛法

积性函数筛法 很多常用的数论函数都是积性函数,而在题目中,我们常常需要线性(甚至更高)的筛法. 对于积性函数,我们可以在筛素数的基础上稍加修改,即可完成线性筛. 首先,注意到积性函数的特点: \[ f(xy)=f(x)\times f(y) \] 而可以线性筛的积性函数,需要知道以下两个式子的快速求法: \[ f(p)=?\quad f(p^k)=?\\p\in prime \] 其中, \(f(p)\) 大多是直接定义,\(f(p^k)\) 大多是递归定义. 我们来回忆一下素数筛的过程: in

数论线性筛总结 (素数筛,欧拉函数筛,莫比乌斯函数筛,前n个数的约数个数筛)

线性筛 线性筛在数论中起着至关重要的作用,可以大大降低求解一些问题的时间复杂度,使用线性筛有个前提(除了素数筛)所求函数必须是数论上定义的积性函数,即对于正整数n的一个算术函数 f(n),若f(1)=1,且当a,b互质时f(ab)=f(a)f(b),在数论上就称它为积性函数,若a,b不互质也满足的话则称作完全积性函数,下面说明每个筛子是怎么筛的. 最基础的是素数筛,其它三个筛都是以素数筛为前提 素数筛 void get_prime() { int pnum = 0; for(int i = 2;

浅谈一类积性函数的前缀和(转载)

本文转自:http://blog.csdn.net/skywalkert/article/details/50500009 另外,莫比乌斯反演和杜教筛其他可转到 http://blog.leanote.com/post/totziens/%E8%8E%AB%E6%AF%94%E4%B9%8C%E6%96%AF%E5%8F%8D%E6%BC%94 写在前面 笔者在刷题过程中遇到一些求积性函数前缀和的问题,其中有一类问题需要在低于线性时间复杂度的算法,今天就来浅析一下这类问题的求解方法,当作以后讲课

jzp线性筛及其简单应用

前言: 很久以前看过了线性筛,没怎么注意原理,但是后来发现线性筛还有很有用的.. 比如上次做的一道题就需要找出每个数的最小质因子,先筛再找就太慢了..一看线性筛发现就可以直接在筛的过程中处理出来了! 今天又学习了屌炸天的jzp线性筛,可以在o(n)的时间内求出欧拉函数, 莫比乌斯函数等积性函数 原理: 首先jzp线性筛并不是一种新的线性筛..其实就是jzp大牛对线性筛的一些开发应用 先回忆一下积性函数的定义 若a,b互质 则f(ab)=f(a)*f(b)的函数f 定义为积性函数,不要求a,b互质