题目大意
有一个函数 f ( x ) f(x) f(x),满足以下性质:
- f ( 1 ) = 1 f(1)=1 f(1)=1
- f ( p c ) = p ⊕ c f(p^c)=p \oplus c f(pc)=p⊕c( p p p为质数, ⊕ \oplus ⊕表示异或)
- f ( a b ) = f ( a ) f ( b ) f(ab)=f(a)f(b) f(ab)=f(a)f(b)( a a a与 b b b互质)
求 ∑ i = 1 n f ( i ) \sum\limits_{i=1}^nf(i) i=1∑nf(i)对 ( 1 0 9 + 7 ) (10^9+7) (109+7)取模的结果,其中 1 ≤ n ≤ 1 0 10 1\leq n\leq 10^{10} 1≤n≤1010。
题解
前置知识:min25筛
观察函数 f ( x ) f(x) f(x), f ( x ) f(x) f(x)在质数和质数的幂的位置比较好求,我们考虑使用min25筛。
当 x x x为奇质数时, f ( x ) = x ⊕ 1 = x − 1 f(x)=x \oplus 1=x-1 f(x)=x⊕1=x−1。当 x x x为偶质数时, f ( x ) = x ⊕ 1 = x + 1 f(x)=x \oplus 1=x+1 f(x)=x⊕1=x+1。令 p ( x ) = x − 1 p(x)=x-1 p(x)=x−1,用 p p p函数代替 f f f函数,然后将 p p p函数分为 f 1 ( x ) = x f_1(x)=x f1(x)=x和 f 2 ( x ) = 1 f_2(x)=1 f2(x)=1两个完全积性函数来求min25筛中的 g g g函数,最后再用 f f f函数的性质来求min25筛中的 S S S函数。对于 p p p和 f f f在 x = 2 x=2 x=2处的差,在最后加上即可。
为什么可以这样呢?由函数 S ( n , i ) S(n,i) S(n,i)的递推式, f ( 2 ) f(2) f(2)的值改变只会影响 S S S的递推式中含有 g g g函数的部分。因为答案为 S ( n , 0 ) + 1 S(n,0)+1 S(n,0)+1,而只有 i = 0 i=0 i=0时才会涉及到 f ( 2 ) f(2) f(2)的值( i ≠ 0 i\neq 0 i=0时两个 g g g函数相减将 f ( 2 ) f(2) f(2)的部分抵消了),所以将 f f f改为 p p p在求答案的情况下只会影响一次,也就是答案减少了 f ( 2 ) − g ( 2 ) = 3 − 1 = 2 f(2)-g(2)=3-1=2 f(2)−g(2)=3−1=2,在最后加上即可。
min25筛中函数 S S S的递推式:
S ( n , i ) = g ( n , ∣ p r ( n ) ∣ ) − g ( p r i , ∣ p r ( n ) ∣ ) + ∑ j > i ∑ p r j k ≤ n f ( p r j k ) × ( S ( ⌊ n p r j k ⌋ , j ) + [ k > 1 ] ) S(n,i)=g(n,|pr(n)|)-g(pr_i,|pr(n)|)+\sum\limits_{j>i}\sum\limits_{pr_j^k\leq n}f(pr_j^k)\times (S(\lfloor\dfrac{n}{pr_j^k}\rfloor,j)+[k>1]) S(n,i)=g(n,∣pr(n)∣)−g(pri,∣pr(n)∣)+j>i∑prjk≤n∑f(prjk)×(S(⌊prjkn⌋,j)+[k>1])
code
#include<bits/stdc++.h>
using namespace std;
const int N=200005;
const long long mod=1000000007;
int p1,vt,z[N+5],pr[N+5];
long long n,x,v[N+5],f[2][N+5],s1[N+5],s2[N+5],g1[N+5],g2[N+5];
void dd(){
for(int i=2;i<=N;i++){
if(!z[i]){
pr[++p1]=i;
s1[p1]=(s1[p1-1]+i)%mod;
s2[p1]=p1;
}
for(int j=1;j<=p1&&i*pr[j]<=N;j++){
z[i*pr[j]]=1;
if(i%pr[j]==0) break;
}
}
}
void init(){
x=sqrt(n)+1;
dd();
for(long long l=1,r;l<=n;l=r+1){
r=n/(n/l);
v[++vt]=n/l;
if(n/l<=x) f[0][n/l]=vt;
else f[1][l]=vt;
long long t=(n/l)%mod;
g1[vt]=(t*(t+1)/2%mod-1+mod)%mod;
g2[vt]=(t-1+mod)%mod;
}
long long w;
for(int i=1;i<=p1;i++){
w=1ll*pr[i]*pr[i];
long long t;
for(int j=1;j<=vt&&w<=v[j];j++){
t=v[j]/pr[i];
if(t<=x) t=f[0][t];
else t=f[1][n/t];
g1[j]=(g1[j]-1ll*pr[i]*(g1[t]-s1[i-1])%mod+mod)%mod;
g2[j]=(g2[j]-1ll*(g2[t]-s2[i-1])%mod+mod)%mod;
}
}
}
long long S(long long p,int q){
if(pr[q]>=p) return 0;
long long td=(p<=x?f[0][p]:f[1][n/p]);
long long re=((g1[td]-g2[td]-s1[q]+s2[q])%mod+mod)%mod;
for(int j=q+1;j<=p1;j++){
if(1ll*pr[j]*pr[j]>p) break;
for(long long o=1,pq=pr[j],t;pq<=p;++o,pq=pq*pr[j]){
t=pq%mod;
re=(re+1ll*(pr[j]^o)%mod*(S(p/pq,j)%mod+(o>1))%mod)%mod;
}
}
return re;
}
int main()
{
scanf("%lld",&n);
init();
if(n==1) printf("1");
else printf("%lld\n",(S(n,0)+3)%mod);
return 0;
}