#莫比乌斯反演,整除分块#洛谷 6222 「P6156 简单题」加强版

题目

多组询问,给出\(n,k\)

\[\sum_{i=1}^n\sum_{j=1}^n(i+j)^kgcd(i,j)\mu^2(gcd(i,j)) \]

\(\text{unsigned}\)自然溢出


分析

推式子

\[=\sum_{d=1}^n\mu^2(d)d^{k+1}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}(i+j)^k[gcd(i,j)==1] \]

\[=\sum_{d=1}^n\mu^2(d)d^{k+1}\sum_{t=1}^{\lfloor\frac{n}{d}\rfloor}\mu(t)t^k\sum_{i=1}^{\lfloor\frac{n}{td}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{td}\rfloor}(i+j)^k \]

后面这一坨可以预处理出来,记作\(F\)
然后枚举\(D=td\)
那么

\[=\sum_{D=1}^nF(\frac{n}{D})D^k\sum_{d|D}d\mu^2(d)\mu(\frac{D}{d}) \]

后面这一坨是一个积性函数,分类讨论一下就可以了


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
typedef unsigned uit;
const uit N=20000011; bool v[N];
uit dp[N],f[N],prime[N],Cnt;
inline uit iut(){
	rr uit ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(uit ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline uit ksm(uit x,uit y){
	rr uit ans=1;
	for (;y;y>>=1,x=x*x)
	    if (y&1) ans=ans*x;
	return ans;
}
inline void Pro(uit n,uit k){
	dp[1]=f[1]=1;
	for (rr uit i=2;i<=n;++i){
		if (!v[i]) prime[++Cnt]=i,f[i]=ksm(i,k),dp[i]=i-1;
		for (rr uit j=1;j<=Cnt&&prime[j]<=n/i;++j){
			v[i*prime[j]]=1,f[i*prime[j]]=f[i]*f[prime[j]];
			if (i%prime[j]==0){
				rr uit t=i/prime[j];
				if (t%prime[j]) dp[i*prime[j]]=-prime[j]*dp[t];
				break;
			}
			dp[i*prime[j]]=dp[i]*(prime[j]-1);
		}
	}
	for (rr uit i=2;i<=n;++i) dp[i]=dp[i-1]+dp[i]*f[i];
	for (rr uit i=2;i<=n;++i) f[i]+=f[i-1];
	for (rr uit i=2;i<=n;++i) f[i]+=f[i-1];
}
inline uit F(uit n){return f[n<<1]-f[n]-f[n];}
signed main(){
	rr uit Test=iut(),MX=iut(); Pro(MX<<1,iut());
	for (rr uit ans=0,i=1;i<=Test;++i,ans=0){
		rr uit n=iut();
		for (rr uit l=1,r;l<=n;l=r+1)
		    r=n/(n/l),ans+=(dp[r]-dp[l-1])*F(n/l);
		print(ans),putchar(10);
	}
	return 0;
}
posted @ 2020-06-03 21:28  lemondinosaur  阅读(149)  评论(0编辑  收藏  举报