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();
}