【题解】Loj6053 简单的函数
\(\text{Solution:}\)
显然的 Min_25 筛。因为题目已经告诉我们:函数是积性函数,并且素数及其次幂处的点值可以快速计算。
先把给的函数拆成若干完全积性函数的和:我们观察到,当 \(p\) 为质数的时候, \(f(p)=p-1.\) 所以我们可以把函数拆成 \(f(p)=p,f(p)=1\) 这两个来分别计算出 \(g_1(n,j),g_2(n,j)\) 数组。
但是对于 \(2\) 这个性质不成立怎么办?考虑计算答案的时候去掉影响就可以了,先按照 \(1\) 算即可。
于是线性筛的时候我们需要维护一下素数的和,至于 \(1\) 这一部分自己算也行,为了板子化也可以求一下前缀和。
同样地,记录下基本和组,并把所有数都当成质数来计算 \(g,\) 因为最后用到的只有素数的部分。
考虑合并答案,实际上就是一样的式子:不断提出 \(p[i]\) 直到把因子提干净,一步步计算即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
const int N=2e5+10;
inline int Add(int x,int y) {
return (x+y)%mod;
}
inline int Mul(int x,int y) {
return 1ll*x*y%mod;
}
inline int dec(int x,int y) {
return (x-y+mod)%mod;
}
bool vis[N];
int p[N],sum1[N],cnt,sq,sp,id1[N],id2[N],g1[N],n,g2[N],w[N],m,sum2[N];
void pre() {
for(int i=2; i<=sq; ++i) {
if(!vis[i])p[++cnt]=i;
for(int j=1; j<=cnt&&i*p[j]<=sq; ++j) {
vis[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
for(int i=1; i<=cnt; ++i) {
sum2[i]=Add(sum2[i-1],p[i]);
sum1[i]=sum1[i-1]+1,sum1[i]%=mod;
}
}
inline int f2(int x) {
x%=mod;
return x*(x+1)/2%mod;
}
inline int getid(int x) {
if(x<=sq)return id1[x];
return id2[n/x];
}
inline int S(int x,int j) {
if(p[j]>x)return 0;
int Ans=dec(dec(g2[getid(x)],g1[getid(x)]),dec(sum2[j],sum1[j]));
if(j==0&&x>=2)Ans=Add(Ans,2);
for(int i=j+1; i<=cnt&&p[i]*p[i]<=x; ++i) {
for(int e=1,sp=p[i]; sp<=x; sp*=p[i],++e) {
Ans=Add(Ans,Mul((p[i]^e)%mod,Add(S(x/sp,i),(e>1))));
}
}
return Ans;
}
signed main() {
scanf("%lld",&n);
sq=sqrt(n);
pre();
for(int l=1,r; l<=n; l=r+1) {
int d=n/l;
r=n/d;
w[++m]=d;
g1[m]=(w[m]-1+mod)%mod;
g2[m]=f2(w[m])-1;
g2[m]+=mod;g2[m]%=mod;
if(w[m]<=sq)id1[w[m]]=m;
else id2[r]=m;
}
for(int i=1; i<=cnt; ++i) {
for(int j=1; j<=m&&p[i]*p[i]<=w[j]; ++j) {
g1[j]=dec(g1[j],dec(g1[getid(w[j]/p[i])],sum1[i-1]));
g2[j]=dec(g2[j],Mul(p[i],dec(g2[getid(w[j]/p[i])],sum2[i-1])));
}
}
printf("%lld\n",(S(n,0)+mod+1)%mod);
return 0;
}