HDU5608 function(杜教筛)
题目大意
给出一个函数其满足
N
2
−
3
N
+
2
=
∑
d
∣
N
f
(
d
)
N^2-3N+2=\sum_{d|N}f(d)
N2−3N+2=d∣N∑f(d)
求
∑
i
=
1
n
f
(
i
)
\sum_{i=1}^nf(i)
∑i=1nf(i)
解题思路
很明显的杜教筛,它甚至帮你把需要构造的卷积给出来了,对着做就行了。可以发现原函数本质就是莫比乌斯函数卷积上那个多项式,为了方便求前缀和,得把多项式拆开和莫比乌斯函数卷积,这样卷积得结果就是积性函数了,就可以方便得线性求出了
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int size=1e6+5;
const int mod=1e9+7;
int p[size],tot,mu[size];
int minn_prime[size];
bool prime[size];
int f2[size],f1[size];
int f[size];
int inv6;
unordered_map<int,int> mp;
int quick_pow(int a,int b){int ans=1;while(b){if(b&1) ans=1LL*ans*a%mod;a=1LL*a*a%mod;b>>=1;}return ans;}
void init()
{
mu[1]=1;f2[1]=1;f1[1]=1;
for(int i=1;i<size;i++) prime[i]=true;
for(int i=2;i<size;i++)
{
if(prime[i])
{
p[++tot]=i;
mu[i]=-1;
minn_prime[i]=i;
f1[i]=i-1;
f2[i]=(1LL*i*i%mod-1+mod)%mod;
}
for(int j=1;j<=tot&&p[j]*i<size;j++)
{
prime[i*p[j]]=false;minn_prime[i*p[j]]=p[j];
if(i%p[j]==0)
{
mu[i*p[j]]=0;
f1[i*p[j]]=f1[i]*p[j];
f2[i*p[j]]=1LL*f2[i]*p[j]%mod*p[j]%mod;
break;
}
else {
mu[i*p[j]]=-mu[i];
f1[i*p[j]]=f1[i]*f1[p[j]];
f2[i*p[j]]=1LL*f2[i]*f2[p[j]]%mod;
}
}
}
for(int i=1;i<size;i++) f[i]=(f2[i]-3LL*f1[i]+mod)%mod;
f[1]=(f[1]+2)%mod;
f[0]=0;
for(int i=1;i<size;i++) f[i]=(f[i-1]+f[i])%mod;
inv6=quick_pow(6,mod-2);
}
int Sum2(int n)
{
return 1LL*n*(n+1)%mod*(2*n+1)%mod*inv6%mod;
}
int Sum1(int n)
{
return 1LL*(n+1)*n/2%mod;
}
int S(int n)
{
if(n<size) return f[n];
if(mp.count(n)) return mp[n];
int ans=(Sum2(n)-3LL*Sum1(n)+2*n)%mod;
for(int l=2,r;l<=n;l=r+1)
{
r=n/(n/l);
ans=(ans-1LL*(r-l+1)*S(n/l)%mod+mod)%mod;
}
return mp[n]=ans;
}
int main()
{
init();
int t;
int n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
if(n<size)
{
printf("%d\n",f[n]);
}
else
{
printf("%d\n",S(n));
}
}
}