bzoj3944: Sum

本文介绍了积性函数的概念及其线性筛法,并详细解释了杜教筛算法的原理与应用。通过实例展示了如何利用杜教筛算法求解特定数论函数的前N项和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接

  http://www.lydsy.com/JudgeOnline/problem.php?id=3944

求积性函数前N项的线性算法

  积性函数是数论函数,且满足当 gcd(a,b)=1 时, f(a)f(b)=f(ab)
  依据这一点,可以得到积性函数的线性筛法。
  显然,当 x 是素数时,f(x)可以根据定义求出。
  当 x 不是素数时,令x=ab a x最小非1约数(显然是素数), b=xa ,当 gcd(a,b)=1 时,可以直接 f(x)=f(a)f(b) 求出。当 gcd(a,b)=a 时,可以根据定义得到 f(x) 。(不同函数根据各自的定义求出即可)
  具体地,边筛素数边做。对于每个数 i ,枚举比它的最小质因子小的所有素数primej,这样就可以去求 f(i×primej)=f(i)f(primej) 。对于 i 的最小质因子p,根据定义求出 f(ip) 。这样可以保证筛法的线性,因为每个数只会被其最小质因子筛去。
  这个方法有局限性,当 gcd(a,b)=a 时,如果不能根据定义方便的求出 f(ab) 的值,那就不能做了。
  那么可以根据积性,把 x 分解成acb a 还是最小的质因子,b是剩下的因子,这时 f(x)=f(ac)f(b)

狄利克雷(dirichlet)卷积

  两个数论函数 f(x)g(x)
  其 dirichlet 卷积:
  

(fg)(x)=d|xf(d)g(xd)

   dirichlet 卷积的性质:
  交换律、结合律、分配律、
   fϵ=f
  特殊性质: μ1=ϵ

杜教筛

  杜教筛,我也不知道怎么得出来的,只会背公式。
  欲求

S(n)=i=1nf(i)

  有一个公式
g(1)S(n)=i=1n(fg)(i)i=2ng(i)S(ni)

  对于不同的 f() 函数,要选择不同的 g() 来卷。
  这样就能够得到 S 的递推式,直接记忆化搜索的时间复杂度是O(N34)
  预处理前 N23 项再记忆化搜索的时间复杂度是 O(N23)

证明莫比乌斯反演定理

  学了 drichlet 卷积之后,证明莫比乌斯反演就容易了。
  莫比乌斯反演定理:
  

f=g1g=μf

   预备知识:
  单位函数 ϵ={01i>1i=1
  首先有个性质 fϵ=f
   充分性:
  
f=g1

  卷 μ
  
fμ=gϵ=g

   必要性:
  
g=fμ

  卷 1
  
g1=fμ1=fϵ=f

  因此 f=g1 g=fμ 互为充要条件

题解

  呼~终于能够写题解了。
  对于

s(n)=i=1nϕ(i)

  由杜教筛的式子(卷 1 )得到
  
s(n)=i=1nd|iϕ(d)i=2ns(ni)

  有个性质 d|nϕ(d)=n ,所以
  
s(n)=n(1+n)2i=2ns(ni)

  同理对于 μ() ,两边也卷 1
  
s(n)=1i=2nS(ni)

代码

//杜教筛
#include <cstdio>
#include <algorithm>
#define maxn 1700000
#define ll long long
using namespace std;
ll N, mu[maxn], phi[maxn], f[maxn], g[maxn], prime[maxn], mark[maxn], T, vis[maxn];
void init()
{
    ll i, j;
    phi[1]=mu[1]=1;
    for(i=2;i<maxn;i++)
    {
        if(!mark[i])prime[++prime[0]]=i, phi[i]=i-1, mu[i]=-1;
        for(j=1;j<=prime[0] and i*prime[j]<maxn;j++)
        {
            mark[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                mu[i*prime[j]]=0;
                break;
            }
            mu[i*prime[j]]=-mu[i];
            phi[i*prime[j]]=phi[i]*phi[prime[j]];
        }
    }
    for(i=2;i<maxn;i++)phi[i]+=phi[i-1],mu[i]+=mu[i-1];
}
inline ll getf(ll n){return n<maxn?phi[n]:f[N/n];}
inline ll getg(ll n){return n<maxn?mu[n]:g[N/n];}
void calc(ll n)
{
    ll i, t=N/n, last;
    if(n<maxn)return;
    if(vis[t]!=T)vis[t]=T;else return;
    f[t]=n*(1+n)/2;
    g[t]=1;
    for(i=2;i<=n;i=last+1)
    {
        last=n/(n/i);
        calc(n/i);
        f[t]-=getf(n/i)*(last-i+1);
        g[t]-=getg(n/i)*(last-i+1);
    }
}
int main()
{
    init();
    for(scanf("%lld",&T);T;T--)
    {
        scanf("%lld",&N);
        calc(N);
        printf("%lld %lld\n",getf(N),getg(N));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值