博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

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;
}
posted @ 2018-01-25 19:25  SovietPower  阅读(425)  评论(2编辑  收藏  举报