題目描述
求
多組數據,,至多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);
}
}