积性函数求和小记

积性函数求和小记

(写了一下syf的讨论题,感觉有点压力,所以就去学了一手233)
这位博主很懒,什么都没有留下,整理理论参考下面这位博主:
https://www.cnblogs.com/peng-ym/p/9446555.html

模板题:P4213 【模板】杜教筛(Sum)
AC code:(没开O2优化过了,开了反而没过,玄学优化233)

#include<bits/stdc++.h>
#include<tr1/unordered_map>
using namespace std;
//using namespace tr1;
typedef long long ll;
const int maxn = 5e6;
bool isprime[maxn + 5];
int prime[maxn],cntp,mu[maxn];
ll phi[maxn];
tr1::unordered_map<int, int>mpu; //代替map,加快速度
tr1::unordered_map<int, ll>mpp; 
void init(){
    memset(isprime,1,sizeof(isprime));
    isprime[0] = isprime[1] = 0;
    phi[1] = mu[1] = 1;
    cntp = 0;
    for(int i = 2; i <= maxn; ++i){
        if(isprime[i]){
            prime[++cntp] = i, phi[i] = i - 1, mu[i] = -1;
        }
        for(int j = 1; j <= cntp && i * prime[j] <=maxn; ++j){
            isprime[i * prime[j]] = 0;
            if(i % prime[j] == 0){
                phi[i * prime[j]] = phi[i] * prime[j],
                mu[i * prime[j]] = 0;
                break ;
            }
            phi[i * prime[j]] = phi[i] * (prime[j] - 1);
            mu[i * prime[j]] = -mu[i];
        }
    }
    for(int i = 2; i <= maxn; ++i){
        mu[i] += mu[i - 1];
        phi[i] += phi[i - 1];
    }
}

int calc_mu(int x){
    if(x <= maxn) return mu[x];
    if(mpu[x]) return mpu[x];
    int res = 1;
    for(unsigned int l = 2,r;  l <= x; l = r + 1){ //可能爆int,比如r = 2147483647
        r = x / (x / l);
        res -= calc_mu(x / l) * (r - l + 1);
    }
    return mpu[x] = res;
}

ll calc_phi(int x){
    if(x <= maxn) return phi[x];
    if(mpp[x])  return mpp[x];
    ll res =  1LL * x * (x + 1) / 2;
    for(unsigned int l = 2, r; l <= x; l = r + 1){ //
        r = x / (x / l);
        res -= calc_phi(x / l) * (r - l + 1);
    }
    return mpp[x] = res;
}

int main(){
    init();
    int T,n;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        printf("%lld %d\n", calc_phi(n), calc_mu(n));
    }
    return 0;
}

求t(n)的前缀和,t(n)表示n的约数个数:
code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
// 返回1->n每个数约数(因子)的个数和
// T = O(sqrt(n))
ll calc(ll n){
    ll res = 0;
    for(ll l = 1, r; l <= n; l = r + 1){
        r = n / (n / l); 	// 与(n/i)大小相同的最末尾的位置
        res += (n / l) * (r - l + 1); // 当前大小乘以区间个数;
    }
    return res;
}

int main(){
    ll n;
    while(~scanf("%lld", &n)){
        printf("%lld\n",calc(n));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值