Description
Solution
(Min25) 筛.
要求出 ((1+p_1⊕c_1)*(1+p_2⊕c_2)*....*(1+p_m⊕c_m)) .
我们可以枚举最小质因子 (p) , 那么就要求剩下选的数都不含小于 (p) 的质因子 , 也就是 (p) 作为最小质因子 .
设 (S(n,k)) 表示当前要求 (sum_{i=2}^{n}f[i]) , 且最小质因子要为 (p[k]) 的贡献 , (p_k) 是第 (k) 个质数.
那么枚举 (i>k) , 并枚举 (p[i]) 的次数 (c) , 然后递归做 (S(frac{n}{p[i]^c},i)) 即可.
要做这个 , 就要快速求出一段的质因子的 (f(i)) 的和.
于是我们预处理出 (s(i)) 表示小于等于 (i) 的质因子的 (f) 之和 .
方法就是枚举所有质数 , 设 (g(n,i)) 表示已经用 (p_1,p_2,p_3,...,p_i) 筛完了 ([2,n]) 后剩余的数的贡献和.
也就是说 (g(n,i)=sum_{j=2}^{n})[(j) 的最小质因子>=(i)或者 (j) 是质数](*f[j]).
不满足上述条件的数已经被减去了 , 所以不需要被重复减去.
当 (p_i*p_i>n) 时 , (g(n,i)=g(n,i-1)).
否则 (g(n,i)=g(n,i-1)-(g(frac{n}{p_i},i-1)-g(p_i,i-1))*f(p_i)) .
实现有一定小技巧 , 参见代码 .
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10,mod=1e9+7;
ll n,s[N],c[N],w[N],p[N];int m=0,sqr,cnt=0;
inline int id(ll x){return x<=sqr?x:m-(n/x)+1;}
//每个数在c,w,s数组中的下标,小于sqrt的显然是本身,否则就是后者.
inline int S(ll n,int k){
if(n<=p[k])return 0;
int ret=(s[id(n)]-s[p[k]]+mod)%mod;//一段区间的质因子的f之和.
for(int i=k+1;i<=cnt && n/p[i]>=p[i];i++){//枚举最小质因子
int c=1;
for(ll j=n;(j/=p[i])>=p[i];c++)//枚举次数
ret=(ret+1ll*(p[i]^c)*S(j,i)+(p[i]^(c+1)))%mod;
}
return ret;
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
cin>>n;
sqr=sqrt(n);
for(ll i=1,j;i<=n;i=j+1){
w[++m]=j=n/(n/i);
//由于S(n,k)中的n只会是n的约数,所以只需要预处理所有约数的贡献和就行了.
s[m]=(j&1?(j+1)/2*j:j/2*(j+1))-1;c[m]=j-1;
//n为10^10,会爆long long,所以先除再乘.
//s[i]是小于等于i的质数和,c[i]是小于等于i的质数个数.
}
for(int i=2,t;i<=sqr;i++){
if(c[i]==c[i-1])continue;//c[i]==c[i-1]说明这个数不是质数
p[++cnt]=i;
for(int j=m;w[j]/i>=i;j--)
s[j]-=(s[t=id(w[j]/i)]-s[i-1])*i,c[j]-=c[t]-c[i-1];
}
//由于f(pi)=pi^1,所以除了f(2)=2+1以外,其他的都是f(p)=f(p)-1
for(int i=2;i<=m;i++)s[i]-=c[i]-2;
cout<<(S(n,0)+1)%mod;
return 0;
}