Description
Input
一共T+1行
第1行为数据组数T(T<=10)
第2~T+1行每行一个非负整数N,代表一组询问
Output
一共T行,每行两个用空格分隔的数ans1,ans2
Sample Input
6
1
2
8
13
30
2333
Sample Output
1 1
2 0
22 -2
58 -3
278 -3
1655470 2
HINT
传送门
天天做裸题我没救了……
第一问见bzoj4805
不过这题里
ϕ
的前缀和我记为了S,待会儿看代码可能要注意。
莫比乌斯函数刚看不久,性质还记得几个,
那么这个就有用了:
∑d|iμ(d)=x
当i=1,x=1;i>1,x=0
那么同样的套路,令
M(n)=∑ni=1μ(i)
那么推导如下:
∑i=1n∑d|iμ(d)=1=∑k=1n∑i=1⌊n/k⌋μ(i)//重要步骤,仔细体会=∑k=1nM(⌊n/k⌋)所以∑k=1nM(⌊n/k⌋)=M(n)+∑k=2nM(⌊n/k⌋)=1M(n)=1−∑k=2nM(⌊n/k⌋)
然后记忆化搜索即可,O( n23 )。
由于n很大,所以要用map或者哈希的方法来存。
map强行多一个log。。于是我就光荣被卡。。
后面看到一些题解用map过了,只是增大了预处理的量,
想想觉得线性筛真的不烂,所以调到了250W,竟然11s-卡过了= =
汗。。
注意一下n=2^31-1的时候开long long的问题。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int
maxn=2500000;
ll S[maxn],M[maxn];
int mu[maxn],phi[maxn],prime[maxn];
bool notprime[maxn];
map<int,ll>f;
void Pre(){
notprime[1]=1,mu[1]=1,phi[1]=1;
int pcnt=0;
S[1]=1,M[1]=1;
for (int i=2;i<maxn;i++){
if (!notprime[i]){
mu[i]=-1,phi[i]=i-1;
prime[++pcnt]=i;
}
for (int j=1;j<=pcnt;j++){
if (prime[j]*i>=maxn) break;
notprime[prime[j]*i]=1;
if (i%prime[j]){
mu[i*prime[j]]=-mu[i];
phi[i*prime[j]]=phi[i]*(prime[j]-1);
} else{
mu[i*prime[j]]=0;
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
}
S[i]=S[i-1]+(ll)phi[i],M[i]=M[i-1]+(ll)mu[i];
}
}
ll solve_phi(int n){
if (n<maxn) return S[n];
if (f[n]) return f[n];
ll ans=(ll)n*(1LL+n)/2LL,last;
for (ll i=2;i<=n;i=last+1){
last=n/(n/i);
ans-=solve_phi(n/i)*(last-i+1);
}
f[n]=ans;
return ans;
}
ll solve_mu(int n){
if (n<maxn) return M[n];
if (f[n]) return f[n];
ll ans=1LL,last;
for (ll i=2;i<=n;i=last+1){
last=n/(n/i);
ans-=solve_mu(n/i)*(last-i+1);
}
f[n]=ans;
return ans;
}
int main(){
Pre();
int n,cas;scanf("%d",&cas);
while (cas--){
scanf("%d",&n);
f.clear(),printf("%lld ",solve_phi(n));
f.clear(),printf("%lld\n",solve_mu(n));
}
return 0;
}