积性函数求和
(全是套路.jpg)
首先观察这个函数,发现是 \(f(n)=\prod_j(p_j^{k_j}+1)\)(设 \(n\) 质因数分解得到 \(\prod_jp_j^{k_j}\))
然后不知怎么想到的,就等价于 \(f(n)=\sum_{d|n} [d\bot \frac nd]d\)。
终于有了比较靠谱的形式,然后就开始推:
\[\sum _{i=1}^nf(i)\\=\sum _{i=1}^n\sum_{d|i} [d\bot \frac id]d\\=\sum _{d=1}^nd\sum_{d|i} [d\bot \frac id]\\=\sum _{d=1}^nd\sum_{i=1}^{\lfloor\frac nd\rfloor} [d\bot i]\\=\sum _{d=1}^nd\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{t|d,t|i}\mu(t)\\=\sum _{d=1}^nd\sum_{t|d}\mu(t)\lfloor\frac n{dt}\rfloor\\=\sum_{T=1}^n\lfloor\frac nT\rfloor\sum _{t^2|T}\mu(t)\frac Tt\\=\sum_{t=1}^{\sqrt n}\frac {\mu(t)}t\sum_{t^2|T}T\lfloor\frac nT\rfloor\\=\sum_{t=1}^{\sqrt n}\frac {\mu(t)}t\sum_{T=1}^{\lfloor\frac n{t^2}\rfloor}Tt^2\lfloor\frac n{Tt^2}\rfloor\\=\sum_{t=1}^{\sqrt n}\mu(t)t\sum_{T=1}^{\lfloor\frac n{t^2}\rfloor}T\lfloor\frac{\lfloor\frac n{t^2}\rfloor}{T}\rfloor\\
\]
后面那个求和号显然可以除法分块 \(O(\frac{\sqrt n}t)\) 求,则
\[\sum_{t=1}^\sqrt n \frac{ \sqrt n}t=\sqrt n\sum_{t=1}^\sqrt n \frac{1}t\sim \sqrt n\ln n
\]
总复杂度 \(O(\sqrt n\ln n)\)。
然后由于毒瘤出题人把 \(n\) 出到了 \(10^{13}\),你发现你被卡常数了 \爆筋
- 瓶颈在除法分块,把这个除法分块写成比较快的版本,可以快至少一倍;
- 注意到 \(g(n)=\sum_{T=1}^nT\lfloor\frac n{T}\rfloor=\sum_{i=1}^n\sigma(i)\) ,这玩意可以线筛。于是把较小的 \(g\) 拿去线筛预处理一下,省下的计算也比较可观。
至此大概就可以过了。
#include<cstdio>
typedef long long ll;
const int D=3.2e6;
int M,p[D],np[D],k,mu[D],t0[D],t1[D],s,sig[D];ll n;
inline int G(ll n){
if(n<D)return sig[n];
int res=0;ll d,e,i;
e=n%M;
for(i=1;i*i<=n;i++){
d=e,e=n/(i+1)%M;
res=(res+i*d*2)%M;
if(n>=i*(i+1))res=(res+(d-e)*(d+e+1)%M*i)%M;
}
return res;
}
int main(){
scanf("%lld%d",&n,&M);
mu[1]=1,sig[1]=1;
for(int i=2;i<D;i++){
if(!np[i])p[++k]=i,mu[i]=-1,t0[i]=t1[i]=1;
if(t1[i]==1)sig[i]=sig[t0[i]]+i;
else sig[i]=sig[t1[i]]*sig[i/t1[i]];
for(int j=1;j<=k&&i*p[j]<D;j++){
np[i*p[j]]=1;
t0[i*p[j]]=i;
if(i%p[j]){
mu[i*p[j]]=-mu[i];
t1[i*p[j]]=i;
}
else{
t1[i*p[j]]=t1[i];
break;
}
}
}
for(int i=1;i<D;i++)sig[i]=(sig[i]*2+sig[i-1])%M;
for(ll i=1;i*i<=n;i++)if(mu[i])
s=(s+G(n/(i*i))*mu[i]*i)%M;
if(s<0)s+=M;
if(s&1)s+=M;
printf("%d\n",s>>1);
return 0;
}
浙公网安备 33010602011771号