[BZOJ3944][杜教筛]Sum

BZOJ3944

杜教筛模板题:
对于 ∑ i = 1 n μ i \sum_{i=1}^n{\mu_i} i=1nμi,有 μ ∗ I = ϵ \mu*I=\epsilon μI=ϵ,由 μ \mu μ的性质或者容斥原理得到
对于 ∑ i = 1 n ϕ i \sum_{i=1}^n{\phi_i} i=1nϕi,有 ϕ ∗ I = I d \phi*I=Id ϕI=Id,将 ϕ i \phi_i ϕi看做是有多少个分母为 i i i的最简真分数,则对于 1 − n 1-n 1n的所有数,都只对一个 d ∣ n d|n dn ϕ d \phi_d ϕd有1的贡献,则通过分母类统计得到 ϕ ∗ I = I d \phi*I=Id ϕI=Id

Code:

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define ll long long
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int P=8e6+7,N=P-7,INF=0x7fffffff;
int pri[P],cnt,mu[P];
bool pt[P];
ll phi[P];
inline void init(){
	phi[1]=mu[1]=1;
	for(int i=2;i<=N;i++){
		if(!pt[i]) pri[++cnt]=i,phi[i]=i-1,mu[i]=-1;
		for(int j=1;j<=cnt && i*pri[j]<=N;j++){
			pt[i*pri[j]]=1;
			if(i%pri[j]==0){
				phi[i*pri[j]]=phi[i]*pri[j];
				mu[i*pri[j]]=0;
				break;
			}
			phi[i*pri[j]]=phi[i]*(pri[j]-1);
			mu[i*pri[j]]=-mu[i];
		}
		mu[i]+=mu[i-1];
		phi[i]+=phi[i-1];
	}
}

namespace solve_mu{
	tr1::unordered_map<int,int>sum;
	int get(int n){
		if(n<=N) return mu[n];
		if(sum[n]) return sum[n];
		int ans=1;
		for(int i=2,j;j<INF && i<=n;i=j+1){
			j=n/(n/i);
			ans-=(j-i+1)*get(n/i);
		}
		return sum[n]=ans;
	}
}

namespace solve_phi{
	tr1::unordered_map<int,ll>sum;
	ll get(int n){
		if(n<=N) return phi[n];
		if(sum[n]) return sum[n];
		ll ans=n*((ll)n+1)/2;
		for(int i=2,j;j<INF && i<=n;i=j+1){
			j=n/(n/i);
			ans-=(j-i+1)*get(n/i);
		}
		return sum[n]=ans;
	}
}
int main(){
	init();int t=read();
	while(t--){
    	int n=read();
        cout<<solve_phi::get(n)<<" "<<solve_mu::get(n)<<"\n";
	}
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值