HDU.5608.function(杜教筛)
\(Description\)
\(n^2-3n+2=\sum_{d|n}f(d)\)
求\(\sum_{i=1}^nf(i)\ mod \ 10^9+7\).
\(Solution\)
参考.
设\(g(n)=n^2-3n+2\),那么\(f*I=g\)。
如果狄利克雷卷积中左边的一个函数是待求前缀和的,而另外两个函数的前缀和比较好计算,那么就可以简化计算过程。
像之前一样,试着计算一下\(\sum_{i=1}^ng(i)\):
\[\sum_{i=1}^ng(i)=\sum_{i=1}^n\sum_{d|i}f(d)=\sum_{i=1}^n\sum_{d=1}^{\lfloor\frac{n}{i}\rfloor}f(d)
\]
而
\[\begin{aligned}\sum_{i=1}^ng(i)&=\sum_{i=1}^ni^2-3\sum_{i=1}^ni+2n=\frac{n(n+1)(2n+1)}{6}-\frac{3n(n+1)}{2}+2n\\&=\frac{n(n-1)(n-2)}{3}\end{aligned}
\]
step2同之前,就是换做考虑因数贡献的值\(\sum_{i=1}^n\sum_{d|i}f(\frac{i}{d})=\sum_{d=1}^n\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}f(i)\)。
这样\(\sum_{i=1}^nf(i)=\frac{n(n-1)(n-2)}{3}-\sum_{i=2}^n\sum_{d=1}^{\lfloor\frac{n}{i}\rfloor}f(d)\)。
预处理就用线筛和莫比乌斯反演 暴力枚举约数。(枚举到多少最适合我也不知道==经过二分,发现确实是6e5比较好...)
/*
注意:有μ所以会有负的!不能用Mod(x),也不能直接取模(先+mod)
*/
#include<map>
#include<cstdio>
#include<cctype>
#define gc() getchar()
typedef long long LL;
const int N=6e5+1,mod=1e9+7;
int n,mu[N+3],P[N>>1],f[N+3],cnt;
bool Not_P[N+3];
std::map<int,int> ref;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
#define Mod(x) x>=mod?x-=mod:0
void Init()
{
mu[1]=1;
for(int i=2;i<N;++i)
{
if(!Not_P[i]) P[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*P[j]<N;++j)
{
Not_P[i*P[j]]=1;
if(!(i%P[j])) {mu[i*P[j]]=0; break;}
mu[i*P[j]]=-mu[i];
}
}
for(int i=1;i<N;++i)
{
int t=((LL)i*i%mod-3*i%mod+2+mod)%mod;
for(int j=i;j<N;j+=i)
(f[j]+=mu[j/i]*t%mod)%=mod;
// WA: f[j]+=mu[j/i]*t%mod, Mod(f[j]);
}
for(int i=1;i<N;++i) f[i]=((f[i]+f[i-1])%mod+mod)%mod;
//WA:for(int i=1;i<N;++i) sum[i]=sum[i-1]+f[i]%mod, Mod(sum[i]);
}
int FP(LL x,int k)
{
LL t=1;
for(;k;k>>=1,x=x*x%mod)
if(k&1) t=t*x%mod;
return t;
}
const int inv3=FP(3,mod-2);//333333336
int Calc(int n)
{
if(n<N) return f[n];
if(ref.count(n)) return ref[n];
int ans=(1LL*n*(n-1)%mod*(n-2)%mod*inv3%mod);
for(int las,i=2;i<=n;i=las+1)
las=n/(n/i),ans-=1ll*(las-i+1)*Calc(n/i)%mod,ans%=mod;
return ref[n]=(ans+mod)%mod;
}
int main()
{
Init();
for(int t=read();t--;)
{
int n=read();
printf("%d\n",Calc(n));
}
return 0;
}
------------------------------------------------------------------------------------------------------------------------
很久以前的奇怪但现在依旧成立的签名
attack is our red sun $$\color{red}{\boxed{\color{red}{attack\ is\ our\ red\ sun}}}$$ ------------------------------------------------------------------------------------------------------------------------
很久以前的奇怪但现在依旧成立的签名
attack is our red sun $$\color{red}{\boxed{\color{red}{attack\ is\ our\ red\ sun}}}$$ ------------------------------------------------------------------------------------------------------------------------