一道莫比乌斯反演练习题

题意

在这里插入图片描述
n < = 1 e 9 n<=1e9 ,答案对 2 32 2^{32} 取膜
部分分 n < = 1 e 6 n<=1e6 , n < = 1 e 7 n<=1e7
首先发现 m u ( i j ) = m u ( i ) m u ( j ) [ g c d ( i , j ) = = 1 ] mu(i*j)=mu(i)*mu(j)*[gcd(i,j)==1]
然后反演掉最后的 [ g c d ( i , j ) = = 1 ] [gcd(i,j)==1] 就可以 O ( n l o g n ) O(nlogn)
对于 n < = 1 e 6 n<=1e6 ,就可以直接做了
但是这个做法常数很小,所以加一些常数优化,就可以通过 n < = 1 e 7 n<=1e7

#include<bits/stdc++.h>
using namespace std;
#define int unsigned int//无符号整型速度很快
const int maxn=1e7+5;
inline int read(){
	char c=getchar();int t=0,f=1;
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
int mu[maxn],p[maxn],vis[maxn],n,cnt;
void get(){
	mu[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]){
			p[++cnt]=i;mu[i]=-1;
		}
		for(int j=1;i*p[j]<=n&&j<=cnt;j++){
			vis[i*p[j]]=1;
			mu[i*p[j]]=mu[i]*mu[p[j]];
			if(i%p[j]==0){
				mu[i*p[j]]=0;
				break;
			}
		}
	}
}
int alfa[maxn];
signed main(){
	//freopen("T2.in","r",stdin);
	//freopen("T2.out","w",stdout);
	n=read();
	get();
	for(int i=n;i>=1;i--){
		int tmp=n/i;
		if(i*2<=n)//这里是常数优化
		alfa[i]=alfa[i*2];
		for(int j=1;j<=tmp;j+=2)//注意这里的步长
		alfa[i]=alfa[i]+mu[i*j];
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		int tmp=mu[i]*alfa[i]*alfa[i];
		ans=ans+tmp;
	}
	printf("%u\n",ans);
	return 0;
}

发布了62 篇原创文章 · 获赞 1 · 访问量 984

猜你喜欢

转载自blog.csdn.net/wmhtxdy/article/details/103875695