d(n) d ( n ) 表示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 个质数
num[i] n u m [ i ] 表示 i i 的最小质因子出现次数
首先我们可以观察一下线性筛素数:
void prepare() {
for (int i=2;iif (!no[i]) sshu[++tot]=i;
for (int j=1;j<=tot&&sshu[j]*ino[sshu[j]*i]=1;
if (i%sshu[j]==0) {
no[sshu[j]*i]=1;
break;
}
}
}
}
我们之所以可以保证上述算法是线性的
就是因为:if (i%sshu[j]==0) break;
也就是说,每个数只会被ta的最小质因子筛掉
很显然, d[n]=2,num[n]=1 d [ n ] = 2 , n u m [ n ] = 1
这种情况下, i i 没有 prime[j] p r i m e [ j ] 这个质因子
然而 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] p r i m e [ j ]
而且 prime[j] p r i m e [ j ] 也必定是 i i 的最小质因数
而 i∗prime[j] i ∗ p r i m e [ j ] 比起 i i 则是多了一个最小质因子
d[i]=(a1+1)(a2+1)...(ak+1) d [ i ] = ( a 1 + 1 ) ( a 2 + 1 ) . . . ( a k + 1 )
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;iif (!no[i]) {
sshu[++tot]=i;
d[i]=2; num[i]=1;
}
for (int j=1;j<=tot&&sshu[j]*iint 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(n) s d ( n ) 表示 n n 的所有约数之和
再次百度一下,我们就可以得到一种比较暴力的 sd s d 计算方法
设 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 个质数
sp[i] s p [ i ] 表示 i i 的 (1+p1+p21+...+pa11) ( 1 + p 1 + p 1 2 + . . . + p 1 a 1 )
显然 sd[n]=n+1,sq[n]=n+1 s d [ n ] = n + 1 , s q [ n ] = n + 1
这种情况, i i 中不包含 prime[j] p r i m e [ j ] 这个质因子
而且 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 i 中至少包含了一个 prime[j] 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+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;iif (!no[i]) {
sshu[++tot]=i;
sd[i]=i+1;
sp[i]=i+1;
}
for (int j=1;j<=tot&&sshu[j]*iint 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;
}
}
}