算法模板题系列(3):杜教筛

本文详细介绍了杜教筛(Sum)算法的实现过程,包括mu、I、id、phi等函数的定义,并给出了常数N的取值。通过初始化计算phi和mu数组,以及求和数组summu1和sumphi1,实现了快速计算前N个正整数的phi和mu的累计值。同时,文章还展示了如何通过动态计算优化大数值的求和,以提高效率。最后,给出了完整的C++代码实现和主函数,用于输入任意正整数n并输出其phi和mu的累计值。
摘要由CSDN通过智能技术生成

P4213 【模板】杜教筛(Sum)

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
/*
μ:mu 
I:I(n)=1
id:id(n)=n
φ:phi
μ ∗ I = ϵ
φ ∗ I = id
μ ∗ id = φ 
*/
const int N=4000000;
int n;
int mu[N+10],phi[N+10];
int summu1[N+10];
int sumphi1[N+10];
int vismu[N+10],visphi[N+10];
int prime[N+10],tot,vis[N+10];
unordered_map<int,int>sumphi2,summu2;
void main_init(){
    mu[1]=phi[1]=1;
    for(int i=2;i<=N;i++){
        if(!vis[i]){
            prime[++tot]=i;
            mu[i]=-1;
            phi[i]=i-1;
        }
        for(int j=1;j<=tot&&i*prime[j]<=N;j++){
            int k=prime[j]*i;
            vis[k]=1;
            if(i%prime[j]){
                mu[k]=-1*mu[i];
                phi[k]=phi[i]*(prime[j]-1);
            }
            else{
                mu[k]=0;
                phi[k]=phi[i]*prime[j];
                break;
            }
        }
    }
    for(int i=1;i<=N;i++){
        summu1[i]=summu1[i-1]+mu[i];
        sumphi1[i]=sumphi1[i-1]+phi[i];
    }
}
void init(){
    // for(int l=1,r,t=n/l;l<=n&&t>N;l=r+1,t=n/l){
    //     r=n/t;
    //     vismu[r]=visphi[r]=0;
    // }
    summu2.clear();
    sumphi2.clear();
}
pair<int,int> get(int m){
    if(m<=N)return {sumphi1[m],summu1[m]};
    if(summu2.find(m)!=summu2.end())return {sumphi2[m],summu2[m]};
    int ans1=1,ans2=m*(m+1)/2;
    for(int l=2,r;l<=m;l=r+1){
        r=m/(m/l);
        auto t=get(m/l);
        ans2-=(r-l+1)*t.first;
        ans1-=(r-l+1)*t.second;
    }
    return {sumphi2[m]=ans2,summu2[m]=ans1};
}
void solve(){
    cin>>n;
    init();
    auto t=get(n);
    cout<<t.first<<" "<<t.second<<endl;
}
signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cout<<fixed<<setprecision(12);
    int t=1;
    main_init();
    cin>>t;
    while (t--)
		solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值