传送门
题解:
设 f ( i ) = σ 0 ( i k ) f(i)=\sigma_0(i^k) f(i)=σ0(ik),显然由于 σ 0 ( i ) \sigma_0(i) σ0(i)是一个积性函数,则 σ 0 ( i k ) \sigma_0(i^k) σ0(ik)是一个积性函数。
以下介绍的是min_25求积性函数前缀和的第二部分,第一部分请参考LOJ6235
显然这道题的质数点值前缀和直接算质数个数后乘上 k + 1 k+1 k+1就行了。
考虑把所有点值的前缀和算出来。
设 S ( n , i ) = ∑ j = 2 n [ m i n p r ( j ) ≥ p i ] f ( j ) S(n,i)=\sum\limits_{j=2}^n[minpr(j)\geq p_i]f(j) S(n,i)=j=2∑n[minpr(j)≥pi]f(j)。
则我们要求的就是 S ( n , 1 ) + f ( 1 ) S(n,1)+f(1) S(n,1)+f(1),补上 1 1 1处的点值。
质数的答案显然已经有了,就是 g ( n , ∣ P ∣ ) − ∑ j = 1 i − 1 f ( p j ) g(n,|P|)-\sum_{j=1}^{i-1}f(p_j) g(n,∣P∣)−∑j=1i−1f(pj)
那么根据函数的积性,我们枚举最小质因子和最小质因子的次数转移就行了。
方程为 S ( n , i ) = g ( n , ∣ P ∣ ) − ∑ j = 1 i − 1 f ( p j ) + ∑ j = i p j 2 ≤ n ∑ t = 1 p j t + 1 ≤ n S ( ⌊ n p j t ⌋ , j + 1 ) ⋅ f ( p j t ) + f ( p j t + 1 ) S(n,i)=g(n,|P|)-\sum_{j=1}^{i-1}f(p_j)+\sum_{j=i}^{p_j^2\leq n}\sum_{t=1}^{p_j^{t+1}\leq n}S(\lfloor\frac{n}{p_j^t}\rfloor,j+1)\cdot f(p_j^t)+f(p_j^{t+1}) S(n,i)=g(n,∣P∣)−j=1∑i−1f(pj)+j=i∑pj2≤nt=1∑pjt+1≤nS(⌊pjtn⌋,j+1)⋅f(pjt)+f(pjt+1)
不需要记忆化,时间复杂度不受影响。
记忆化的优化效果也微乎其微,因为子问题重叠率不高。
代码:
#include<bits/stdc++.h>
#define ll unsigned long long
#define re register
#define cs const
cs int N=1e6+7;
int lim,tot,p[N];
ll f1[N],f2[N];
ll n,k;
inline void init(){
lim=sqrt(n);tot=0;
for(int re i=1;i<=lim;++i)f1[i]=i-1,f2[i]=n/i-1;
for(int re p=2;p<=lim;++p)if(f1[p]!=f1[p-1]){
::p[++tot]=p;ll t=f1[p-1];
for(int re i=1,li=lim/p;i<=li;++i)f2[i]-=f2[i*p]-t;
for(int re i=lim/p+1,li=std::min(n/p/p,(ll)lim);i<=li;++i)f2[i]-=f1[n/i/p]-t;
if((ll)p*p<=lim)for(int re i=lim,li=p*p;i>=li;--i)f1[i]-=f1[i/p]-t;
}
}
ll solve(ll n,int i){
ll g=(n<=lim)?f1[n]:f2[::n/n];
ll ans=(k+1)*(g-f1[p[i-1]]);
for(int re j=i;j<=tot;++j){
if((ll)p[j]*p[j]>n)break;
for(ll now=p[j],t=1;now<=n;now*=p[j],++t){
if(now*p[j]<=n)ans+=(k*t+1)*solve(n/now,j+1);
if(t>1)ans+=(k*t+1);
}
}
return ans;
}
signed main(){
int T;std::cin>>T;
while(T--){
std::cin>>n>>k;init();
std::cout<<solve(n,1)+1<<"\n";
}
return 0;
}