数论:积性函数求和练习集

1.莫比乌斯函数求和

基准时间限制:3 秒 空间限制:131072 KB 分值: 320  难度:7级算法题
 收藏
 关注
莫比乌斯函数,由德国数学家和天文学家莫比乌斯提出。梅滕斯(Mertens)首先使用μ(n)(miu(n))作为莫比乌斯函数的记号。具体定义如下:
如果一个数包含平方因子,那么miu(n) = 0。例如:miu(4), miu(12), miu(18) = 0。
如果一个数不包含平方因子,并且有k个不同的质因子,那么miu(n) = (-1)^k。例如:miu(2), miu(3), miu(30) = -1,miu(1), miu(6), miu(10) = 1。

给出一个区间[a,b],S(a,b) = miu(a) + miu(a + 1) + ...... miu(b)。
例如:S(3, 10) = miu(3) + miu(4) + miu(5) + miu(6) + miu(7) + miu(8) + miu(9) + miu(10)
= -1 + 0 + -1 + 1 + -1 + 0 + 0 + 1 = -1。
Input
输入包括两个数a, b,中间用空格分隔(2 <= a <= b <= 10^10)
Output
输出S(a, b)。
Input示例
3 10
Output示例
-1


①式怎么化简出来的呢?参考一个经典问题:求1~n的约数之和。除了计算每个数的贡献之外我们还能这样:

根据上面的原理就能理解①式了,于是计算M(n)就能采用递归的方法完成。

# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 6e6;
int mu[maxn+3], prime[maxn+3];
bool bo[maxn+3];
map<LL,LL>mp;
void get()//莫比乌斯函数打表
{
    mu[1]=1;
    for(int i=2; i<=maxn; ++i)
    {
        if(!bo[i])
        {
            prime[++prime[0]] = i;
            mu[i] = -1;
        }
        for(int j=1; j<=prime[0]&&prime[j]*i<=maxn; ++j)
        {
            bo[i*prime[j]] = 1;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]] = 0;
                break;
            }
            else mu[i*prime[j]] = -mu[i];
        }
    }
    for(int i=1; i<=maxn; ++i)
        mu[i] += mu[i-1];
}
LL cal(LL n)
{
    if(n<=maxn) return mu[n];
    if(mp.count(n)) return mp[n];
    LL ans = 0;
    for(LL l=2,r; l<=n; l=r+1)//分块加速,因为n/i相同的值有很多个。
    {
        r=n/(n/l);
        ans += (r-l+1)*cal(n/l);
    }
    ans = 1-ans;
    mp[n] = ans;
    return ans;
}
int main()
{
    get();
    LL a, b;
    scanf("%lld%lld",&a,&b);
    printf("%lld\n",cal(b)-cal(a-1));//作差即可
    return 0;
}


2.欧拉函数求和

基准时间限制:3 秒 空间限制:131072 KB 分值: 320  难度:7级算法题
 收藏
 关注
对正整数n,欧拉函数是小于或等于n的数中与n互质的数的数目。此函数以其首名研究者欧拉命名,它又称为Euler's totient function、φ函数、欧拉商数等。例如:φ(8) = 4(Phi(8) = 4),因为1,3,5,7均和8互质。
S(n) = Phi(1) + Phi(2) + ...... Phi(n),给出n,求S(n),例如:n = 5,S(n) = 1 + 1 + 2 + 2 + 4 = 10,定义Phi(1) = 1。由于结果很大,输出Mod 1000000007的结果。
Input
输入一个数N。(2 <= N <= 10^10)
Output
输出S(n) Mod 1000000007的结果。
Input示例
5
Output示例
10


跟上题同一个套路。

# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 6e6;
const LL mod = 1e9+7;
bool bo[maxn+3];
LL phi[maxn+3], prime[maxn+3], two;
map<LL,LL>mp;
LL qmod(LL a, LL b, LL c)
{
    LL ans=1LL;
    for(;b;b>>=1)
    {
        if(b&1) ans=ans*a%c;
        a=a*a%c;
    }
    return ans;
}
void get()//欧拉函数打表
{
    phi[1] = 1;
    two = qmod(2, mod-2, mod);//2在该模数下的逆元
    for(LL i=2; i<=maxn; ++i)
    {
        if(!bo[i])
        {
            prime[++prime[0]] = i;
            phi[i] = i-1;
        }
        for(LL j=1; j<=prime[0]&&i*prime[j]<=maxn; ++j)
        {
            bo[i*prime[j]] = 1;
            if(i%prime[j] == 0)
            {
                phi[i*prime[j]] = prime[j]*phi[i];
                break;
            }
            else phi[i*prime[j]] = (prime[j]-1)*phi[i];
        }
    }
    for(int i=1; i<=maxn; ++i)//欧拉函数前缀和
        phi[i] = (phi[i-1]+phi[i])%mod;
}
LL cal(LL n)
{
    if(n<=maxn) return phi[n];
    if(mp.count(n)) return mp[n];
    LL ans = 0;
    for(LL l=2,r; l<=n; l=r+1)//分块加速,因为n/i相同的值有很多个。
    {
        r=n/(n/l);
        ans += (r-l+1)%mod*cal(n/l)%mod;
        ans %= mod;
    }
    ans = (((n%mod*((n+1)%mod)%mod*two%mod-ans)%mod)+mod)%mod;
    mp[n] = ans;
    return ans;
}
int main()
{
    get();
    LL n;
    scanf("%lld",&n);
    printf("%lld\n",cal(n));
    return 0;
}

3.HDU5608 function

Problem Description
There is a function  f(x),which is defined on the natural numbers set  N,satisfies the following eqaution

N23N+2=d|Nf(d)

calulate  Ni=1f(i)   mod 109+7.
 

Input
the first line contains a positive integer T,means the number of the test cases.

next T lines there is a number N


T500,N109

only  5 test cases has  N>106.
 

Output
Tlines,each line contains a number,means the answer to the  i-th test case.
 

Sample Input
 
  
13
 

Sample Output
 
  
2$1^2-3*1+2=f(1)=0$$2^2-3*2+2=f(2)+f(1)=0->f(2)=0$$3^2-3*3+2=f(3)+f(1)=2->f(3)=2$$f(1)+f(2)+f(3)=2$
 

Source

同样的套路,直接递归计算是 O(n^(3/4))会超时,考虑对前面部分预处理下,根据下面的经典变换。
# include <iostream>
# include <cstdio>
# include <map>
# include <algorithm>
using namespace std;
typedef long long LL;
const LL mod = 1e9+7;
const int maxn = 1e6;
map<LL,LL>mp;
LL six, two, sum[maxn+3];
int prime[maxn+3], mu[maxn+3];
bool bo[maxn+3];
LL qmod(LL a, LL b, LL c)
{
    LL ans = 1;
    for(;b;b>>=1)
    {
        if(b&1) ans=ans*a%c;
        a=a*a%c;
    }
    return ans;
}
void pre()
{
    mu[1] = 1;
    for(int i=2; i<=maxn; ++i)
    {
        if(!bo[i])
        {
            prime[++prime[0]] = i;
            mu[i] = -1;
        }
        for(int j=1; j<=prime[0]&&prime[j]*i<=maxn; ++j)
        {
            bo[i*prime[j]] = 1;
            if(i%prime[j] == 0)
            {
                mu[i*prime[j]] = 0;
                break;
            }
            else mu[i*prime[j]] = -mu[i];
        }
    }
    for(int i=1; i<=maxn; ++i)
    {
        for(int j=i; j<=maxn; j+=i)
        {
            sum[j] += mu[j/i]*((1LL*i*i-1LL*3*i+2)%mod+mod)%mod;
            sum[j] = (sum[j]+mod)%mod;
        }
        sum[i] = (sum[i]+sum[i-1])%mod;
    }
}
LL cal(LL n)
{   if(n<=maxn) return sum[n];
    if(mp.count(n)) return mp[n];
    LL ans = 1LL*n%mod*((n+1)%mod)%mod*((2*n+1)%mod)%mod*six%mod;
    ans = (ans-n%mod*((n+1)%mod)%mod*3%mod*two%mod+mod)%mod;
    ans = (ans+n*2%mod)%mod;
    for(LL l=2, r; l<=n; l=r+1)
    {
        r = n/(n/l);
        ans = (ans-(r-l+1)%mod*cal(n/l)%mod+mod)%mod;
    }
    mp[n] = ans;
    return ans;
}
int main()
{
    pre();
    LL n;
    int t;
    six = qmod(6, mod-2, mod);
    two = qmod(2, mod-2, mod);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&n);
        printf("%lld\n",cal(n));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值