线性筛求积性函数

白天拍了一天马原视频,欠了一堆实验报告没写,昨晚cf鸽了,牛客数学专题班欠一堆题,外加感冒,今晚的cf应该也鸽了…这两场补题看情况了

先开始第一个问题:求正整数 n ( 1 ≤ n ≤ 1 0 7 ) n(1\le n\le 10^7) n(1n107)的所有正因数的个数, q ( 1 ≤ q ≤ 1 0 5 ) q(1\le q\le10^5 ) q(1q105)次询问 例题

我们规定 n n n的正因子数目为 d ( n ) d(n) d(n) n n n的最小质因子出现次数为 e ( n ) e(n) e(n)
n = p 1 k 1 p 2 k 2 . . . p c k c ( p 1 < p 2 < . . . < p c ) n={p_1}^{k_1}{p_2}^{k_2}...{p_c}^{k_c}({p_1}\lt{p_2}\lt...\lt{p_c}) n=p1k1p2k2...pckc(p1<p2<...<pc)
d ( n ) = ∏ i = 1 c ( k i + 1 ) d(n)=\prod_{i=1}^c(k_i+1) d(n)=i=1c(ki+1)
e ( n ) = k 1 e(n)=k_1 e(n)=k1
显然 d ( n ) d(n) d(n)是一个积性函数: 对于 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1 d ( a × b ) = d ( a ) × d ( b ) d(a\times b)=d(a)\times d(b) d(a×b)=d(a)×d(b)恒成立

线性筛 d ( n ) d(n) d(n):

#include <bits/stdc++.h>
using namespace std;
const int N=1e7+10;
typedef long long ll;
ll d[N],e[N],prime[N],c;
void solve(){
    d[1]=1;
    for(int i=2;i<N;i++){
        if(d[i]==0){
            prime[c++]=i;
            d[i]=2;
            e[i]=1;
        }
        for(int j=0;1LL*prime[j]*i<N;j++){
            if(i%prime[j]==0){
                d[i*prime[j]]=d[i]/(e[i]+1)*(e[i]+2);
                e[i*prime[j]]=e[i]+1;
                break;
            }
            d[i*prime[j]]=d[i]*d[prime[j]];
            e[i*prime[j]]=1;
        }
    }
}
int main(){
    ll q,n;
    scanf("%lld",&q);
    solve();
    while(q--){
        scanf("%lld",&n);
        printf("%lld\n",d[n]);
    }
    return 0;
}

华华给月月出题
A n s = ⊕ i = 1 N ( i N m o d ( 1 0 9 + 7 ) ) Ans=\oplus_{i=1}^N(i^N mod(10^9+7)) Ans=i=1N(iNmod(109+7)) ( ⊕ \oplus 表示异或和) ( 1 ≤ N ≤ 1.3 × 1 0 7 ) (1\le N\le 1.3\times 10^7) (1N1.3×107)
对于 f ( i ) = i N f(i)=i^N f(i)=iN,显然有 f ( i × j ) = f ( i ) × f ( j ) f(i\times j)=f(i)\times f(j) f(i×j)=f(i)×f(j)恒成立,那么我们称这种函数为完全积性函数
那么我们对每个素数直接用快速幂求出 f f f,线性筛求出其余的 f f f,最后再求异或和即可

Code

#include <bits/stdc++.h>
using namespace std;
const int N=2e7+10,mod=1e9+7;
typedef long long ll;
ll power(ll a,ll b){
    ll ans=1;
    for(;b;b>>=1){
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;
    }
    return ans;
}
ll prime[N],fac[N],n,cnt;
bool vis[N];
void solve(){
    fac[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i]) {
            prime[++cnt]=i;
            fac[i]=power(i,n);
        }
        for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
            vis[i*prime[j]]=1;
            fac[i*prime[j]]=fac[i]*fac[prime[j]]%mod;
            if(i%prime[j]==0) break;
        }
    }
}
int main(){
    cin>>n;
    solve();
    ll ans=0;
    for(int i=1;i<=n;i++) ans^=fac[i];
    cout<<ans<<endl;
    return 0;
}

下面我们介绍一下线性筛求莫比乌斯函数

莫比乌斯函数
μ ( n ) = { 1 若 n = 1 ; ( − 1 ) k 若 n 无 平 方 因 子 数 , 且 n = p 1 ∗ p 2 . . . . p c ; 0 若 n 有 平 方 因 子 数 \mu(n)=\begin{cases} 1\qquad若n=1;\\(-1)^k 若n无平方因子数,且n=p_1*p_2....p_c;\\0 \qquad若n有平方因子数\end{cases} μ(n)=1n=1;(1)knn=p1p2....pc;0n
显然 μ ( n ) \mu(n) μ(n)是一个积性函数,那么如何用线性筛求出这个积性函数
我们考虑三种情况如下:
1. n = p j c n=p_j^c n=pjc,那么有: μ ( p j ) = − 1 \mu(p_j)=-1 μ(pj)=1, μ ( n ) = 0 , c > 1 \mu(n)=0,c>1 μ(n)=0,c>1
2. n = i × p j n=i\times p_j n=i×pj p j ∣ i p_j\mid i pji,那么有: μ ( n ) = 0 \mu(n)=0 μ(n)=0
3. n = i × p j n=i\times p_j n=i×pj p j ∤ i p_j\nmid i pji,那么有: μ ( n ) = − μ ( i ) \mu(n)=-\mu(i) μ(n)=μ(i)

Code:

int prime[N],mu[N],vis[N],n,c;
void get_mu(){
    mu[1]=1;
	for(int i=2;i<N;i++){
		if(vis[i]==0){
			prime[c++]=i;
			mu[i]=-1;
		}
		for(int j=0;1LL*prime[j]*i<N;j++){
			vis[i*prime[j]]=1;
			if(i%prime[j]==0){
				mu[i*prime[j]]=0;
				break;
			}
			mu[i*prime[j]]=-mu[i];
		}
	}
}

在了解莫比乌斯函数之后,那么我们就有必要深入了解有关莫比乌斯反演相关的数论知识…

又忙又想摆烂,真是没救了

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学不会数据库

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值