d d 函数
表示n的约数个数和
百度一下,我们就可以得到一个计算d函数的暴力做法
设
n=pa11pa22...pakk
n
=
p
1
a
1
p
2
a
2
.
.
.
p
k
a
k
d(n)=(a1+1)(a2+1)...(ak+1)
d
(
n
)
=
(
a
1
+
1
)
(
a
2
+
1
)
.
.
.
(
a
k
+
1
)
显然d是一个积性函数,我们可以用线性筛求出
设
prime[i]
p
r
i
m
e
[
i
]
表示第
i
i
个质数
表示
i
i
的最小质因子出现次数
首先我们可以观察一下线性筛素数:
void prepare() {
for (int i=2;i<N;i++) {
if (!no[i]) sshu[++tot]=i;
for (int j=1;j<=tot&&sshu[j]*i<N;j++) {
no[sshu[j]*i]=1;
if (i%sshu[j]==0) {
no[sshu[j]*i]=1;
break;
}
}
}
}
我们之所以可以保证上述算法是线性的
就是因为:if (i%sshu[j]==0) break;
也就是说,每个数只会被ta的最小质因子筛掉
① 当前数是质数
很显然,
②i%prime[j]!=0
这种情况下,
i
i
没有这个质因子
然而
i∗prime[j]
i
∗
p
r
i
m
e
[
j
]
中包含了一个
prime[j]
p
r
i
m
e
[
j
]
前面我们已经得到了
d[i]
d
[
i
]
d[i]=(a1+1)(a2+1)...(ak+1)
d
[
i
]
=
(
a
1
+
1
)
(
a
2
+
1
)
.
.
.
(
a
k
+
1
)
然后我们在这之后补上一个
prime[j]
p
r
i
m
e
[
j
]
d[i∗prime[j]]=(a1+1)(a2+1)...(ak+1)(1+1)
d
[
i
∗
p
r
i
m
e
[
j
]
]
=
(
a
1
+
1
)
(
a
2
+
1
)
.
.
.
(
a
k
+
1
)
(
1
+
1
)
d[i∗prime[j]]=d[i]∗d[prime[j]]=d[i]∗2
d
[
i
∗
p
r
i
m
e
[
j
]
]
=
d
[
i
]
∗
d
[
p
r
i
m
e
[
j
]
]
=
d
[
i
]
∗
2
而且由于当前的 prime[j] p r i m e [ j ] 必然是 i∗prime[j] i ∗ p r i m e [ j ] 的最小素因子(因为从小到大枚举), 我们要记录下这个最小素因子的个数
num[i∗prime[j]]=1 n u m [ i ∗ p r i m e [ j ] ] = 1
③i%prime[j]=0
这种情况下,i中必然包含了至少一个
prime[j]
p
r
i
m
e
[
j
]
而且
prime[j]
p
r
i
m
e
[
j
]
也必定是
i
i
的最小质因数
而比起 i i 则是多了一个最小质因子
d[i∗prime[j]]=(a1+1+1)(a2+1)...(ak+1)
d
[
i
∗
p
r
i
m
e
[
j
]
]
=
(
a
1
+
1
+
1
)
(
a
2
+
1
)
.
.
.
(
a
k
+
1
)
那么
d[i∗prime[j]]=d[i]/(a1+1)∗(a1+2)
d
[
i
∗
p
r
i
m
e
[
j
]
]
=
d
[
i
]
/
(
a
1
+
1
)
∗
(
a
1
+
2
)
num[i∗prime[j]]=num[i]+1
n
u
m
[
i
∗
p
r
i
m
e
[
j
]
]
=
n
u
m
[
i
]
+
1
void prepare() {
d[1]=1; num[1]=1;
for (int i=2;i<N;i++) {
if (!no[i]) {
sshu[++tot]=i;
d[i]=2; num[i]=1;
}
for (int j=1;j<=tot&&sshu[j]*i<N;j++) {
int v=sshu[j]*i;
no[v]=1;
if (i%sshu[j]==0) {
num[v]=num[i]+1;
d[v]=d[i]/num[v]*(num[v]+1);
break;
}
d[v]=d[i]<<1; num[v]=1;
}
}
//for (int i=1;i<=10;i++) printf("%d\n",d[i]);
}
sd s d 函数
sd(n) s d ( n ) 表示 n n 的所有约数之和
再次百度一下,我们就可以得到一种比较暴力的计算方法
设
n=pa11pa22...pakk
n
=
p
1
a
1
p
2
a
2
.
.
.
p
k
a
k
sd(n)=(1+p1+p21+p31+...+pa11)(1+p2+p22+...+pa22)...(1+p3+p23+...+pa33)
s
d
(
n
)
=
(
1
+
p
1
+
p
1
2
+
p
1
3
+
.
.
.
+
p
1
a
1
)
(
1
+
p
2
+
p
2
2
+
.
.
.
+
p
2
a
2
)
.
.
.
(
1
+
p
3
+
p
3
2
+
.
.
.
+
p
3
a
3
)
又是一个积性函数,我们可以考虑用线性筛筛出sd函数
设
prime[i]
p
r
i
m
e
[
i
]
表示第
i
i
个质数
表示
i
i
的
① 当前数是质数
显然 sd[n]=n+1,sq[n]=n+1 s d [ n ] = n + 1 , s q [ n ] = n + 1
②i%prime[j]!=0
这种情况,
i
i
中不包含这个质因子
而且
prime[j]
p
r
i
m
e
[
j
]
一定是
i∗prime[j]
i
∗
p
r
i
m
e
[
j
]
的最小质因子
sd[i]=(1+p1+p21+...+pa11)(1+p2+p22+...+pa22)...(1+p3+p23+...+pa33)
s
d
[
i
]
=
(
1
+
p
1
+
p
1
2
+
.
.
.
+
p
1
a
1
)
(
1
+
p
2
+
p
2
2
+
.
.
.
+
p
2
a
2
)
.
.
.
(
1
+
p
3
+
p
3
2
+
.
.
.
+
p
3
a
3
)
sd[i∗prime[j]]=(1+p1+p21+...+pa11)...(1+p3+p23+...+pa33)(1+prime[j])
s
d
[
i
∗
p
r
i
m
e
[
j
]
]
=
(
1
+
p
1
+
p
1
2
+
.
.
.
+
p
1
a
1
)
.
.
.
(
1
+
p
3
+
p
3
2
+
.
.
.
+
p
3
a
3
)
(
1
+
p
r
i
m
e
[
j
]
)
sd[i∗prime[j]]=sd[i]∗sd[prime[j]]
s
d
[
i
∗
p
r
i
m
e
[
j
]
]
=
s
d
[
i
]
∗
s
d
[
p
r
i
m
e
[
j
]
]
sp[i∗prime[j]]=sp[prime[j]]=prime[j]+1
s
p
[
i
∗
p
r
i
m
e
[
j
]
]
=
s
p
[
p
r
i
m
e
[
j
]
]
=
p
r
i
m
e
[
j
]
+
1
③i%prime[j]=0
这种情况下, i i 中至少包含了一个
那么:
sd[i]=(1+p1+p21+...+pa11)(1+p2+p22+...+pa22)...(1+p3+p23+...+pa33)
s
d
[
i
]
=
(
1
+
p
1
+
p
1
2
+
.
.
.
+
p
1
a
1
)
(
1
+
p
2
+
p
2
2
+
.
.
.
+
p
2
a
2
)
.
.
.
(
1
+
p
3
+
p
3
2
+
.
.
.
+
p
3
a
3
)
sd[i∗prime[j]]=(1+p1+p21+...+pa11+pa1+11)...(1+p3+p23+...+pa33)
s
d
[
i
∗
p
r
i
m
e
[
j
]
]
=
(
1
+
p
1
+
p
1
2
+
.
.
.
+
p
1
a
1
+
p
1
a
1
+
1
)
.
.
.
(
1
+
p
3
+
p
3
2
+
.
.
.
+
p
3
a
3
)
我们观察一下两式唯一的不同:
(1+p1+p21+...+pa11)
(
1
+
p
1
+
p
1
2
+
.
.
.
+
p
1
a
1
)
(1+p1+p21+...+pa11+pa1+11)
(
1
+
p
1
+
p
1
2
+
.
.
.
+
p
1
a
1
+
p
1
a
1
+
1
)
sd[i∗prime[j]]=sd[i]/(1+p1+p21+...+pa11)∗(1+p1+p21+...+pa11+pa1+11) s d [ i ∗ p r i m e [ j ] ] = s d [ i ] / ( 1 + p 1 + p 1 2 + . . . + p 1 a 1 ) ∗ ( 1 + p 1 + p 1 2 + . . . + p 1 a 1 + p 1 a 1 + 1 )
那么
sd[i∗prime[j]]=sd[i]/sp[i]∗(sp[i]∗prime[j]+1)
s
d
[
i
∗
p
r
i
m
e
[
j
]
]
=
s
d
[
i
]
/
s
p
[
i
]
∗
(
s
p
[
i
]
∗
p
r
i
m
e
[
j
]
+
1
)
sp[i∗prime[j]]=sp[i]∗prime[j]+1
s
p
[
i
∗
p
r
i
m
e
[
j
]
]
=
s
p
[
i
]
∗
p
r
i
m
e
[
j
]
+
1
void prepare() {
sd[1]=1; sp[1]=1;
for (int i=2;i<N;i+=) {
if (!no[i]) {
sshu[++tot]=i;
sd[i]=i+1;
sp[i]=i+1;
}
for (int j=1;j<=tot&&sshu[j]*i<N;j++) {
int v=sshu[j]*i;
no[v]=1;
if (i%sshu[j]==0) {
sp[v]=sp[i]*sshu[j]+1;
sd[v]=sd[i]/sp[i]*sp[v];
break;
}
sd[v]=sd[i]*sd[sshu[j]];
sp[v]=sshu[j]+1;
}
}
}