版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/C20181220_xiang_m_y/article/details/84840730
题目描述
求
多组数据,
,至多5组数据
题目分析
杜教筛其实就是用狄利克雷卷积优化
把
看作
那么可看出
倘若用于卷积的其中一个函数(此处的
)和卷积后的函数(此处的
)很好求前缀和,那么就可以优化求卷积中的另一个函数的前缀和
上式第二行中的
实际上是在枚举第一行中
是
的几倍
这样就使得
连续,便于分块优化,记
把
移到左边,g移到右边,得到
g(i)可以O(1)求,F用分块优化,
但是还是会TLE,需要线性筛出 的F,时间复杂度可以降到
枚举d,暴力更新d的倍数,O(nlnn),其实上述也是莫比乌斯的另类推导。。。
总的来说就是 卷积+线性筛(用到了莫比乌斯反演)
#include<cstdio>
#include<map>
using namespace std;
const int mod = 1e9+7, N = 1000000, inv3 = 333333336;
map<int,int>F;
int T,n,sum[N+5],mu[N+5],p[N+5];
bool v[N+5];
void Prime()
{
mu[1]=1;int cnt=0;
for(int i=2;i<=N;i++)
{
if(!v[i]) p[++cnt]=i,mu[i]=-1;
for(int j=1,k;j<=cnt&&p[j]*i<=N;j++)
{
v[k=p[j]*i]=1;
if(i%p[j]==0) {mu[k]=0;break;}
mu[k]=-mu[i];
}
}
for(int i=1;i<=N;i++)
{
int x=(1ll*i*i-3*i+2)%mod;
for(int j=i;j<=N;j+=i)
sum[j]=(sum[j]+x*mu[j/i])%mod;
}
for(int i=1;i<=N;i++) sum[i]=(sum[i]+sum[i-1])%mod;
}
int solve(int n)
{
if(n<=N) return sum[n];
if(F.count(n)) return F[n];
int ret=(1ll*n*(n+1)%mod*(n-4)%mod*inv3+2*n)%mod;
for(int i=2,j;i<=n;i=j+1)
{
j=n/(n/i);
ret=(ret-1ll*solve(n/i)*(j-i+1))%mod;
}
return F[n]=ret;
}
int main()
{
Prime();
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
printf("%d\n",(solve(n)+mod)%mod);
}
}