BSOJ5655【BZOJ4916】神犇和蒟蒻
题目
求:
\[\large A=\sum_{i=1}^n\mu(i^2),B=\sum_{i=1}^n\varphi(i^2)
\]
分析
首先第一问显然是 \(1\) 。
第二问很容易由结论转化:
\[\large \varphi(nm)=\varphi(n)\varphi(m)\frac{\gcd(n,m)}{\varphi(\gcd(n,m))}
\]
那么就变成了:
\[\large \sum_{i=1}^n\varphi(i^2)=\sum_{i=1}^n\varphi(i)^2\frac i{\varphi(i)}=\sum_{i=1}^ni\cdot \varphi(i)
\]
接下来的任务是求 \(f(x)=id(x)\cdot \varphi(x)\) 的前缀和。
考虑杜教筛,然后根据常见套路,可以卷上 \(id\) :
\[\large (f*id)(n)=\sum_{d\vert n}d\cdot \varphi(d)\cdot\frac nd=n\sum_{d\vert n}\varphi(d)=n^2
\]
考虑这个 \(f\) 的前缀和:\(\large \sum\limits_{i=1}^ni^2=\frac{n(n+1)(2n+1)}{6}\) ,很好求。
再考虑 \(id\) 的前缀和,就是等差数列,也很好求。
那么就可以杜教筛了,这道题结束。
代码
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
x=0;bool f=false;char ch=getchar();
while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
x=f?-x:x;
return ;
}
template <typename T>
inline void write(T x){
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
#define ll long long
#define ull unsigned long long
#define rep(i,x,y) for(int i=(x);i<=(y);i++)
#define dep(i,y,x) for(int i=(y);i>=(x);i--)
const int N=1e7+5,M=2e5+5;
const ll V=1e9,t=1e7,MOD=1e9+7;
int prime[N],cnt,phi[N];
ll n,prep[N],Ans,Rev6,Rev2;
bool isprime[N];
inline ll inc(ll x,ll y){x+=y;return x>=MOD?x-MOD:x;}
inline void incc(ll &x,ll y){x+=y;if(x>=MOD) x-=MOD;}
inline void decc(ll &x,ll y){x-=y;if(x<0) x+=MOD;}
inline ll dec(ll x,ll y){x-=y;return x<0?x+MOD:x;}
bool vis[N];
inline void GetPrimes(ll d){
phi[1]=prep[1]=1;
for(ll i=2;i<=d;i++){
if(!isprime[i]) prime[++cnt]=i,phi[i]=i-1;
prep[i]=inc(prep[i-1],1ll*phi[i]*i%MOD);
for(ll j=1;j<=cnt&&i*prime[j]<=d;j++){
isprime[i*prime[j]]=true;
if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j]%MOD;break;}
phi[i*prime[j]]=phi[i]*(prime[j]-1)%MOD;
}
}
return ;
}
unordered_map<ll,ll>prepp;
inline ll QuickPow(ll x,ll y){
ll res=1;
while(y){
if(y&1) res=res*x%MOD;
x=x*x%MOD;
y>>=1;
}
return res;
}
inline ll Getprephi(ll x){
if(x<=t) return prep[x];//线性筛预处理
if(prepp[x]) return prepp[x];
ll res=1ll*x*(x+1)%MOD*(2*x+1)%MOD*Rev6%MOD;
for(ll l=2,r;l<=x;l=r+1){
r=x/(x/l);
decc(res,1ll*dec(r*(r+1)%MOD*Rev2%MOD,l*(l-1)%MOD*Rev2%MOD)*Getprephi(x/l)%MOD);
}
return prepp[x]=(res+MOD)%MOD;
}
signed main(){
read(n);
GetPrimes(t);
Rev6=QuickPow(6,MOD-2);
Rev2=QuickPow(2,MOD-2);
write(1),putchar('\n');
write(Getprephi(n));
return 0;
}