SP34096 DIVCNTK 题解
SP34096 DIVCNTK 题解
题意:求\(S_k(n)=\sum_{i=1}^{n}d(i^k)\)。
数据范围:多组数据,\(1\le T\le 10^4,n,k\le 10^{10}\)
思路:设\(f(x)=d(x^k)\),发现\(f(p^c)=kc+1\),在质数幂时可以快速求值,于是我们可以用\(Min\_25\)筛。
时间复杂度:\(O(\dfrac{n^{0.75}}{\log n}+n^{1-\epsilon})\)
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 | #include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int N=1e6+5;
int T,sqr;
ll n,k,lmt,num,pri[N],val[N<<1],tot,g[N<<1],id1[N],id2[N];
bool v[N];
inline ll S(ll x,int y){
if(x<pri[y])return 0;
ll t=(x<=sqr?id1[x]:id2[n/x]);
ll ans=g[t]-y*(k+1);
for(int i=y+1;i<=num&&1ll*pri[i]*pri[i]<=x;i++){
ll pe=pri[i];
for(int e=1;pe<=x;e++,pe=pe*pri[i]){
ans+=(k*e+1)*(S(x/pe,i)+(e!=1));
}
}
return ans;
}
int main(){
for(int i=2;i<N;i++){
if(!v[i])pri[++num]=i;
for(int j=1;j<=num&&pri[j]*i<N;j++){
v[i*pri[j]]=1;
if(i%pri[j]==0)break;
}
}
scanf("%d",&T);
while(T--){
scanf("%lld%lld",&n,&k);
sqr=sqrt(n);
for(lmt=1;lmt<=num&&pri[lmt]<=sqr;)lmt++;lmt--;
tot=0;
for(ll l=1,r;l<=n;l=r+1){
r=n/(n/l);
val[++tot]=n/l;
g[tot]=val[tot]-1;
if(n/l<=sqr)id1[n/l]=tot;
else id2[r]=tot;
}
for(int j=1;j<=lmt;j++){
for(int i=1;pri[j]*pri[j]<=val[i];i++){
ll k=val[i]/pri[j];
k=(k<=sqr?id1[k]:id2[n/k]);
g[i]-=(g[k]-j+1);
}
}
for(int i=1;i<=tot;i++)g[i]*=(k+1);
printf("%llu\n",S(n,0)+1);
}
return 0;
}
|