【题解】SP34096 DIVCNTK - Counting Divisors (general)
题目大意:求 \(\sum_{i=1}^n \rho(i^k)\)
观察一下它的性质:(下面简记 \(p\) 为质数)
-
\(f(p)=\rho(p^k)=k+1\)
-
\(f(p^\alpha)=\rho(p^{\alpha k} )=\alpha k+1\)
-
\(f(ab)=\rho((ab)^k)=\rho(a^k)\rho(b^k)=f(a)f(b)[\gcd(a,b)=1]\)
于是它满足:是积性函数,在 \(p,p^k\) 的值可以快速计算。
于是就可以用 Min_25 筛了,复杂度是 \(O(\frac{n^{\frac{3}{4}}}{\log n})\)
这篇题解没有讲关于 Min_25 的具体实现,主要是想要说一下做的时候遇到的问题:
求 Min_25 中 \(g\) 数组的过程中是需要把 \(f(x)\) 拆解成一些完全积性函数的,这个时候我把 \(f(p)=k+1\) 拆成了 \(f_0(p)=1,f_1(p)=k\) 两个函数,乍一看没什么问题,但仔细想想会发现:
\([\gcd(a,b)=1]f(ab)=f(a)f(b)=k^2\not =k\)
所以这个 \(f_1\) 并不是积性函数!
以后拆的时候一定要注意,不能看着像就写上了,要不然调好久都不知道为啥。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
typedef unsigned long long ull;
const int N=2e5+10;
namespace Min_25{
ull T,g1[N],w[N];
ull sp,n,k,id1[N],id2[N];
int sq,cnt,m,p[N],sum1[N];
bool vis[N];
void pre(){
for(int i=2;i<=sq;++i){
if(!vis[i])p[++cnt]=i;
for(int j=1;j<=cnt&&i*p[j]<=sq;++j){
vis[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
for(int i=1;i<=cnt;++i)sum1[i]=sum1[i-1]+1;
}
inline ull f1(ull x){return x;}
inline ull getid(ull x){if(x<=sq)return id1[x];return id2[n/x];}
ull S(ull x,int j){
if(p[j]>x)return 0;
ull Ans=(g1[getid(x)])-(sum1[j]+sum1[j]*k);
for(int i=j+1;i<=cnt&&p[i]*p[i]<=x;++i){
for(int e=1,sp=p[i];sp<=x;sp*=p[i],++e){
Ans+=(k*e+1)*(S(x/sp,i)+(e>1));
}
}
return Ans;
}
inline void write(ull x){
if(x>9)write(x/10);
putchar(x%10+'0');
}
void solve(){
cin>>T;
sq=100000;
pre();
while(T--){
cin>>n>>k;
for(ull l=1,r;l<=n;l=r+1){
ull d=n/l;
w[++m]=d;r=n/d;
g1[m]=f1(w[m])-1;
if(w[m]<=sq)id1[w[m]]=m;
else id2[r]=m;
}
for(int i=1;i<=cnt;++i)
for(int j=1;j<=m&&p[i]*p[i]<=w[j];++j){
g1[j]=g1[j]-(g1[getid(w[j]/p[i])]-sum1[i-1]);
}
for(int j=1;j<=m;++j)g1[j]=g1[j]*(k+1);
write(S(n,0)+1);putchar('\n');
for(int i=1;i<=m;++i)id1[w[m]]=id2[w[m]]=0,g1[i]=w[i]=0;
m=0;
}
}
}
signed main(){
Min_25::solve();
return 0;
}