Sum

题意

给定正整数\(n\),求\(\sum^n_i\phi(i),\sum^n_i\mu(i)\)


思路

由于数据范围过大,本题采用杜教筛解决,在正确的预处理下,可以达到\(O(n^{\frac{2}{3}})\)的优越复杂度。

假定对于积性函数\(f(i)\),我们需要求\(S(n)=\sum^n_if(i)\)

我们假定存在另一个积性函数\(g\),那么\(\sum^n_i(f*g)(i)=\sum^n_i\sum_{d|i}f(d)g(\frac{i}{d})\)

\(g(d)\)提出来就可以得到\(\sum^n_dg(d)S(\frac{n}{d})\)

那么\(g(1)S(d)=\sum^n_{i=1}g(i)S(\frac{n}{i})-\sum^n_{i=2}g(i)S(\frac{n}{i})\)

于是我们可以进行\(O(1)\)求解,查询记忆化即可。

当然光记忆化还是不行,所以我们可以选择预处理一部分,剩下的大的记忆化。

据证明,预处理\(n^{\frac{2}{3}}\)时时间复杂度最优。

代码

#include <bits/stdc++.h>

using namespace std;

namespace StandardIO {

	template<typename T> inline void read (T &x) {
		x=0;T f=1;char c=getchar();
		for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
		for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
		x*=f;
	}
	template<typename T> inline void write (T x) {
		if (x<0) putchar('-'),x=-x;
		if (x>=10) write(x/10);
		putchar(x%10+'0');
	}

}

using namespace StandardIO;

namespace Solve {
	
	const int N=5000000;
	
	static int T,cnt;
	static int isprime[N+5],prime[N+5],mu[N+5];
	static long long phi[N+5];
	static unordered_map<int,long long> rem_phi;
	static unordered_map<int,int> rem_mu;
	
	inline void init () {
		mu[1]=phi[1]=1;
		for (register int i=2; i<=N; ++i) {
			if (!isprime[i]) {
				prime[++cnt]=i,phi[i]=i-1,mu[i]=-1;
			}
			for (register int j=1; j<=cnt&&prime[j]*i<=N; ++j) {
				int k=prime[j]*i;
				isprime[k]=1;
				if (i%prime[j]==0) {
					mu[k]=0;
					phi[k]=phi[i]*prime[j];
					break;
				}
				phi[k]=phi[i]*phi[prime[j]];
				mu[k]=-mu[i];
			}
		}
		for (register int i=1; i<=N; ++i) {
			phi[i]+=phi[i-1],mu[i]+=mu[i-1];
		}
	}
	inline long long calc_phi (int x) {
		if (x<=N) return phi[x];
		if (rem_phi[x]) return rem_phi[x];
		long long ans=(long long)x*(x+1)/2;
		for (register int l=2,nxt; nxt<2147483647&&l<=x; l=nxt+1) {
			nxt=min(x,x/(x/l));
			ans-=(long long)(nxt-l+1)*calc_phi(x/l);
		}
		return rem_phi[x]=ans;
	}
	inline int calc_mu (int x) {
		if (x<=N) return mu[x];
		if (rem_mu[x]) return rem_mu[x];
		int ans=1;
		for (register int l=2,nxt; nxt<2147483647&&l<=x; l=nxt+1) {
			nxt=min(x,x/(x/l));
			ans-=(nxt-l+1)*calc_mu(x/l);
		}
		return rem_mu[x]=ans;
	}

	inline void MAIN () {
		init();
		read(T);
		while (T--) {
			int x;read(x);
			write(calc_phi(x)),putchar(' '),write(calc_mu(x)),putchar('\n');
		}
	}
	
}

int main () {
	Solve::MAIN();
}
posted @ 2019-08-17 16:46  Ilverene  阅读(241)  评论(0编辑  收藏  举报