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}^nsum_{d|i}f(d)=sum_{i=1}^nsum_{d=1}^{lfloorfrac{n}{i} floor}f(d)$$
  而

[egin{aligned}sum_{i=1}^ng(i)&=sum_{i=1}^ni^2-3sum_{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} ]

  (upd:好久没用,不知道博客园怎么改的Latex,不知道哪错了,复制到别的上看叭)
  step2同之前,就是换做考虑因数贡献的值(sum_{i=1}^nsum_{d|i}f(frac{i}{d})=sum_{d=1}^nsum_{i=1}^{lfloorfrac{n}{d} floor}f(i))
  这样(sum_{i=1}^nf(i)=frac{n(n-1)(n-2)}{3}-sum_{i=2}^nsum_{d=1}^{lfloorfrac{n}{i} floor}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
",Calc(n));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/SovietPower/p/8352820.html