[51Nod 1244]

[51Nod 1244] - 莫比乌斯函数之和

i=1Nμ(i)sum_{i=1}^Nμ(i)
开推
dnμ(d)=[n==1]sum_{d|n}mu(d)=[n==1]
移项
μ(d)=[n==1]dn,d<nμ(d)S(N)=i=1Nμ(i)=i=1N([i==1]di,d<iμ(d))=1i=1Ndi,d<iμ(d)mu(d)=[n==1]-sum_{d|n,d<n}mu(d) ewline herefore S(N)=sum_{i=1}^Nμ(i)=sum_{i=1}^N([i==1]-sum_{d|i,d<i}mu(d)) ewline =1-sum_{i=1}^Nsum_{d|i,d<i}mu(d) ewline
此处是杜教筛的精髓,也是整除分块优化的精髓(或者说是转换方法),枚举i是d的多少倍
S(N)=1id=2Nd=1,1<idNidμ(d)S(N)=1-sum_{{lfloor{frac id} floor} =2}^Nsum_{d=1,1<{lfloor{frac id} floor}}^{lfloor frac N{lfloor{frac id} floor} floor}mu(d)
k=idk={lfloor{frac id} floor},则有
S(N)=1k=2Nd=1Nkμ(d)=1k=2NS(Nk)S(N)=1-sum_{k=2}^Nsum_{d=1}^{lfloor frac Nk floor}mu(d) =1-sum_{k=2}^NS({lfloor frac Nk floor})
那么就可以用线性筛出前面一部分,再整除分块优化递归处理
杜教筛无预处理的时间复杂度是Θ(n34)Theta(n^{frac 34})
预处理一定范围内的答案后就能降到Θ(n23)Theta(n^{frac 23})
然而我们此处并不需要多小的时间复杂度…随便处理一个10710^7就能过了

AC code
#include <cstdio>
#include <map>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
const int MAXP = 1e7+1;

int Prime[MAXP/10], Cnt, mu[MAXP], sum[MAXP];
bool IsnotPrime[MAXP];
map<LL,int>S;
void init(int N)
{
	mu[1] = 1;
	for(int i = 2; i <= N; ++i)
	{
		if(!IsnotPrime[i]) Prime[++Cnt] = i, mu[i] = -1;
		for(int j = 1; j <= Cnt && i * Prime[j] <= N; ++j)
		{
			IsnotPrime[i * Prime[j]] = 1;
			if(i % Prime[j] == 0) { mu[i * Prime[j]] = 0; break; }
			mu[i * Prime[j]] = -mu[i];
		}
	}
	for(int i = 1; i <= N; i++) sum[i] = sum[i-1] + mu[i];
}

inline int solve(LL N)
{
	if(N < MAXP) return sum[N];
	if(S.count(N)) return S[N];//记忆化,其实此处可以Hash或者用
	int ret = 1;
	for(LL i = 2, j; i <= N; i=j+1)
	{
		j = N/(N/i);
		ret -= (j-i+1) * solve(N/i);
	}
	return S[N] = ret;
}

int main ()
{
    LL n, m; init(MAXP-1);
    scanf("%lld%lld", &n, &m);
    printf("%d
", solve(m)-solve(n-1));
}

[51Nod 1239] - 欧拉函数之和

i=1Nφ(i)sum_{i=1}^Nφ(i)
开推,有
dnφ(d)=n sum_{d|n}φ(d)=n
移项
φ(n)=ndn,d&lt;nφ(d)S(N)=i=1N(idi,d&lt;iφ(d))=N(N+1)2i=1Ndi,d&lt;iφ(d)=N(N+1)2id=2Nd=1Nidφ(d) φ(n)=n-sum_{d|n,d&lt;n}φ(d) ewline herefore S(N)=sum_{i=1}^N(i-sum_{d|i,d&lt;i}φ(d)) ewline =frac{N*(N+1)}2-sum_{i=1}^Nsum_{d|i,d&lt;i}φ(d) ewline =frac{N*(N+1)}2-sum_{{lfloorfrac id floor}=2}^Nsum_{d=1}^{{lfloorfrac N{{lfloorfrac id floor}} floor}}φ(d) ewline
k=idk={lfloor{frac id} floor},则有
S(N)=N(N+1)2k=2Nd=1Nkφ(d)=N(N+1)2k=2NS(Nk) S(N)=frac{N*(N+1)}2-sum_{k=2}^Nsum_{d=1}^{{lfloorfrac Nk floor}}φ(d) ewline =frac{N*(N+1)}2-sum_{k=2}^NS({lfloorfrac Nk floor}) ewline
然后…就没有了.像上一道题一样处理就完了

AC Code
#include <cstdio>
#include <map>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
const int MAXP = 5e6 + 1;
const int mod = 1e9 + 7;
const int inv2 = 500000004;

int Prime[MAXP/10], Cnt, phi[MAXP];
LL sum_phi[MAXP];
bool IsnotPrime[MAXP];

void init(int N)
{
	phi[1] = 1;
	for(LL i = 2; i <= N; ++i)
	{
		if(!IsnotPrime[i]) Prime[++Cnt] = i, phi[i] = i-1;
		for(LL j = 1; j <= Cnt && i * Prime[j] <= N; ++j)
		{
			IsnotPrime[i * Prime[j]] = 1;
			if(i % Prime[j] == 0)
			{
				phi[i * Prime[j]] = phi[i] * Prime[j];
				break;
			}
			phi[i * Prime[j]] = phi[i] * (Prime[j]-1);
		}
	}
	for(int i = 1; i <= N; i++)
		sum_phi[i] = ((sum_phi[i-1] + phi[i]) % mod + mod) % mod;
}
map<LL, LL> S_phi;
inline LL solve_phi(LL N)
{
	if(N < MAXP) return sum_phi[N];
	if(S_phi.count(N)) return S_phi[N];
	LL ret = (N%mod + 1) * (N%mod) % mod * inv2 % mod;
	for(LL i = 2, j; i <= N; i=j+1)
	{
		j = N/(N/i);
		ret = (ret - (j-i+1) % mod * solve_phi(N/i) % mod) % mod;
	}
	return S_phi[N] = ((ret + mod) % mod);
}
int main ()
{
	init(MAXP-1); LL n;
	scanf("%lld", &n);
	printf("%lld
", solve_phi(n));
}
原文地址:https://www.cnblogs.com/Orz-IE/p/12039464.html