积性函数的前缀和
求积性函数前缀和,线性筛需要把函数的每一位值都算出来,作了许多不必要的操作。
线性筛中,通过计算最小质因子幂的函数值,与之前已计算出的函数值相乘,得到新的函数值。
如果我们能批量执行上面的操作,即用最小质因子幂的函数值,与另一些函数值的和相乘,就可以得到更多的函数值的和。
我们还能发现,当我们要求前 n n n项的和时,大于 n \sqrt n n的质因子都不能用于计算任何其它的积性函数
于是就有了Min_25筛,将质数分为小于等于 n \sqrt n n,和大于 n \sqrt n n的。再预处理出所有质数函数值的前缀和,利用小于等于 n \sqrt n n的质数进行转移,推出所有的函数值的和。
对于积性函数 F ( n ) F(n) F(n)
在 O ( n 3 4 l o g n ) O(\frac {n^{\frac 3 4}} {log\ n}) O(log nn43)的复杂度内求出 ∑ i = 1 n F ( i ) \sum_{i=1}^n F(i) ∑i=1nF(i)。
要求对于每个质数 p p p, F ( p ) F(p) F(p)是简单的多项式, F ( p k ) F(p^k) F(pk)很容易算出。
一般题目 n = 1 0 10 n=10^{10} n=1010左右的数量级
我们需要得到所有质数函数值得前缀和。
首先用线性筛处理出 ≤ n \leq \sqrt n ≤n的质数, p r [ i ] pr[i] pr[i]表示第i个质数。
设原积性函数为 F ( n ) F(n) F(n),即满足若 ( a , b ) = 1 (a,b)=1 (a,b)=1,则 F ( a b ) = F ( a ) F ( b ) F(ab)=F(a)F(b) F(ab)=F(a)F(b)
设 p p p为质数, F ( p ) = f 0 ( p ) + f 1 ( p ) + . . . F(p)=f_0(p)+f_1(p)+... F(p)=f0(p)+f1(p)+...(必须保证 f ( p ) = p k f(p)=p^k f(p)=pk)。
即质数代入原函数中,得到的简单多项式,每一项都拆成一个函数 f f f,下面的过程将对每一个 f f f单独求和。
*注:即使p不是质数,也可以代入f(p)进行计算,但这并不是原来的积性函数的值。
设 g ( i , j ) g(i,j) g(i,j)满足 g ( i , j ) = ∑ k 为 质 数 , 或 k 的 最 小 质 因 子 > p r [ j ] i f ( k ) g(i,j)=\sum_{k为质数,或k的最小质因子> pr[j]}^i f(k) g(i,j)=k为质数,或k的最小质因子>pr[j]∑if(k)
实际上可以发现,上式中的k,即为线性筛筛了j个质数后,剩余没有被筛掉的数。
因为线性筛用 ≤ n \leq \sqrt n ≤n的质数就可以筛掉 n n n以内的合数,所以我们只预处理了 ≤ n \leq \sqrt n ≤n的质数。( g ( n , ∣ p r ∣ ) g(n,|pr|) g(n,∣pr∣)即为n以内所有质数的函数值之和,|pr|为 n \sqrt n n以内的质数个数 )
g ( i , j ) g(i,j) g(i,j)的转移:
当 p r [ j ] 2 > i pr[j]^2>i pr[j]2>i时,显然线性筛中 p r [ j ] pr[j] pr[j]筛不掉任何数,所以 g ( i , j ) = g ( i , j − 1 ) g(i,j)=g(i,j-1) g(i,j)=g(i,j−1)
当 p r [ j ] 2 ≤ i pr[j]^2\leq i pr[j]2≤i时,将上一次的答案减去 p r [ j ] pr[j] pr[j]筛掉的答案,即最小质因子为 p r [ j ] pr[j] pr[j]的合数的函数值之和,将这些数的 p r [ j ] pr[j] pr[j]提出来,剩下的和可以用g表示,公式如下: g ( i , j ) = g ( i , j − 1 ) − f ( p r [ j ] ) ( g ( ⌊ i p r [ j ] ⌋ , j − 1 ) − ∑ k = 1 j − 1 f ( p r [ k ] ) ) g(i,j)=g(i,j-1)-f(pr[j])\left(g\left(\left \lfloor \frac i {pr[j]} \right \rfloor ,j-1\right)-\sum_{k=1}^{j-1}f(pr[k])\right) g(i,j)=g(i,j−1)−f(pr[j])(g(⌊pr[j]i⌋,j−1)−k=1∑j−1f(pr[k]))
初始状态 g ( i , 0 ) g(i,0) g(i,0)为 ∑ k = 2 i f ( k ) \sum_{k=2}^if(k) ∑k=2if(k),不管k是不是质数。。( f ( 1 ) f(1) f(1)需单独处理)
在实现过程中,可以发现最后 g ( i , j ) g(i,j) g(i,j)只需要用到 i = ⌊ n k ⌋ i=\lfloor \frac n k \rfloor i=⌊kn⌋, j = ∣ p r ∣ j=|pr| j=∣pr∣的部分,总共只有 2 n 2\sqrt n 2n个位置,可以离散化处理,后面再讲。
我们现在已经可以通过 g ( i , ∣ p r ∣ ) g(i,|pr|) g(i,∣pr∣)得到所有质数的函数值前缀和,现在要把它扩展到所有数。
设 S ( i , j ) S(i,j) S(i,j),满足 S ( i , j ) = ∑ k 的 最 小 质 因 子 ≥ p r [ j ] i F ( k ) S(i,j)=\sum_{k的最小质因子\geq pr[j]}^iF(k) S(i,j)=k的最小质因子≥pr[j]∑iF(k)
如果 i < p r [ j ] i<pr[j] i<pr[j],显然 S ( i , j ) = 0 S(i,j)=0 S(i,j)=0,现在考虑当 i ≥ p r [ j ] i\geq pr[j] i≥pr[j]时
S ( i , j ) S(i,j) S(i,j)中质数部分很容易算出,为 g ( i , ∣ p r ∣ ) − ∑ k = 1 j − 1 f ( p r [ k ] ) g(i,|pr|)-\sum_{k=1}^{j-1}f(pr[k]) g(i,∣pr∣)−∑k=1j−1f(pr[k])
合数部分,可以枚举合数的最小质因子,和最小质因子的指数,将规模缩小,递归求解。
S ( i , j ) = g ( i , ∣ p r ∣ ) − ∑ k = 1 j − 1 f ( p r [ k ] ) + ∑ k = j p r [ k ] 2 ≤ i ∑ e = 1 p r [ k ] e + 1 ≤ i F ( p r [ k ] e ) × S ( ⌊ i p r [ k ] e ⌋ , k + 1 ) + F ( p r [ k ] e + 1 ) S(i,j)=g(i,|pr|)-\sum_{k=1}^{j-1}f(pr[k])+\sum_{k=j}^{pr[k]^2\leq i}\sum_{e=1}^{pr[k]^{e+1}\leq i}F(pr[k]^e)\times S\left(\left\lfloor \frac i {pr[k]^e}\right\rfloor,k+1\right)+F(pr[k]^{e+1}) S(i,j)=g(i,∣pr∣)−k=1∑j−1f(pr[k])+k=j∑pr[k]2≤ie=1∑pr[k]e+1≤iF(pr[k]e)×S(⌊pr[k]ei⌋,k+1)+F(pr[k]e+1)
末状态为 S ( 1 , j ) = 0 S(1,j)=0 S(1,j)=0,和 S ( i , j ) = 0 ( p r [ j ] > i ) S(i,j)=0\ (pr[j]>i) S(i,j)=0 (pr[j]>i)
*注:因为实际上F(n)被拆成了多个fi函数,实际上式中对f(pr[k])求和部分要将每一个fi函数的值求和
∑ i = 1 n F ( i ) = S ( n , 1 ) + F ( 1 ) \sum_{i=1}^n F(i)=S(n,1)+F(1) i=1∑nF(i)=S(n,1)+F(1)
观察发现我们要求的是 S ( n , 1 ) S(n,1) S(n,1),里面只会访问到 g ( n , ∣ p r ∣ ) g(n,|pr|) g(n,∣pr∣)和 g ( ⌊ n a 1 ⌋ , ∣ p r ∣ ) g(\left\lfloor \frac n {a_1} \right\rfloor,|pr|) g(⌊a1n⌋,∣pr∣), g ( ⌊ n a 1 a 2 ⌋ , ∣ p r ∣ ) g(\left\lfloor \frac {\frac n {a_1}} {a_2} \right\rfloor,|pr|) g(⌊a2a1n⌋,∣pr∣)…
也就是实际上用到的值只有 g ( ⌊ n i ⌋ , ∣ p r ∣ ) g(\left\lfloor \frac n i \right\rfloor,|pr|) g(⌊in⌋,∣pr∣),只有最多 2 n 2\sqrt n 2n个位置,预处理出这些位置,离散化如果 ⌊ n i ⌋ ≤ n \left\lfloor \frac n i \right\rfloor \leq \sqrt n ⌊in⌋≤n用 i d 1 [ ⌊ n i ⌋ ] id1[\left\lfloor \frac n i \right\rfloor] id1[⌊in⌋]存储离散化之后的下标,如果 ⌊ n i ⌋ > n \left\lfloor \frac n i \right\rfloor>\sqrt n ⌊in⌋>n用 i d 2 [ ⌊ n ⌊ n i ⌋ ⌋ ] id2[\left\lfloor \frac n {\left\lfloor \frac n i \right\rfloor}\right\rfloor] id2[⌊⌊in⌋n⌋]存储它的下标。
因为最后只需要用到 g ( ⌊ n i ⌋ , ∣ p r ∣ ) g(\left\lfloor \frac n i \right\rfloor,|pr|) g(⌊in⌋,∣pr∣),所以第二维不需要开数组存储,转移时之间用一维计算即可。
这样空间复杂度就降为了 O ( n ) O(\sqrt n) O(n)
后面求S没什么好说的,直接递归。
不会证
定义积性函数 F ( n ) F(n) F(n)
F ( p c ) = p ⊕ c F(p^c)=p\oplus c F(pc)=p⊕c
发现除了2以外的质数, F ( p ) = p − 1 F(p)=p-1 F(p)=p−1,即可以把F拆成两个f函数
f 0 ( p ) = p f_0(p)=p f0(p)=p
f 1 ( p ) = 1 f_1(p)=1 f1(p)=1
然后分别求和计算,用 g ( i , j ) g(i,j) g(i,j)表示 f 0 f_0 f0的和, h ( i , j ) h(i,j) h(i,j)表示 f 1 f_1 f1的和
在求 S ( i , j ) S(i,j) S(i,j)时,如果 j = 1 j=1 j=1,将答案+2(用于特判p=2)
代码:
#include
#include
#include
using namespace std;
const int MOD=1000000007,MAXN=200005;
long long n,sqr;
bool npr[MAXN];
int pr[MAXN],sum[MAXN],cnt[MAXN],P;
int id1[MAXN],id2[MAXN],m;
long long w[MAXN];
int g[MAXN],h[MAXN];
void LinerSieve()
{
npr[1]=true;
for(int i=2;i<=sqr;i++)
{
if(!npr[i])
{
pr[++P]=i;
sum[P]=(sum[P-1]+i)%MOD;
}
for(int j=1;j<=P&&1LL*i*pr[j]<=sqr;j++)
{
npr[i*pr[j]]=true;
if(i%pr[j]==0)
break;
}
}
}
void Calc_g_h()
{
for(long long i=1,j;i<=n;i=j+1)
{
j=n/(n/i);
w[++m]=n/i;
if(w[m]<=sqr)
id1[w[m]]=m;
else
id2[n/w[m]]=m;
g[m]=(w[m]%MOD+2)*(w[m]%MOD-1)%MOD*(MOD+1)/2%MOD;
h[m]=w[m]%MOD-1;
}
for(int j=1;j<=P;j++)
for(int i=1;i<=m&&1LL*pr[j]*pr[j]<=w[i];i++)
{
long long k=w[i]/pr[j];
k=(k<=sqr)?id1[k]:id2[n/k];
g[i]=(g[i]-1LL*pr[j]*(g[k]-sum[j-1])%MOD+MOD)%MOD;
h[i]=(h[i]-1LL*(h[k]-(j-1))%MOD+MOD)%MOD;
}
}
int S(long long x,int j)
{
if(x<=1||pr[j]>x)
return 0;
int k=(x<=sqr)?id1[x]:id2[n/x];
int res=((g[k]-h[k]-sum[j-1]+(j-1))%MOD+MOD)%MOD;
if(j==1)
res=(res+2)%MOD;
for(int k=j;k<=P&&1LL*pr[k]*pr[k]<=x;k++)
{
long long t=pr[k];
for(int e=1;1LL*pr[k]*t<=x;e++,t*=pr[k])
res=((res+1LL*(pr[k]^e)*S(x/t,k+1)%MOD)%MOD+(pr[k]^(e+1)))%MOD;
}
return res;
}
int main()
{
scanf("%lld",&n);
sqr=sqrt(n);
LinerSieve();
Calc_g_h();
int ans=S(n,1)+1;
printf("%d\n",ans);
return 0;
}