【莫比乌斯反演,欧拉筛】洛谷P2568 GCD

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/88849090

D e s c r i p t i o n Description

链接&多组数据版链接

p p r i m e i = 1 n j = 1 n [ g c d ( i , j ) = p ] \sum_{p\in prime} \sum_{i=1}^n\sum_{j=1}^n[gcd(i,j)=p]

n 1 0 7 n\leq 10^7


本题有两种解法,其一为欧拉函数,另一个为莫比乌斯反演,由于本人实力太弱,暂时只会欧拉的方法,当本人学会莫比乌斯反演的时候再补上,见谅! 2019 / 3 / 27 ——2019/3/27

S o l u t i o n   1 Solution\ 1

g c d gcd 的套路日常相除
p p r i m e i = 1 n p j = 1 n p [ g c d ( i , j ) = 1 ] \sum_{p\in prime} \sum_{i=1}^{\lfloor \frac np\rfloor}\sum_{j=1}^{\lfloor \frac np\rfloor}[gcd(i,j)=1]

由于 g c d ( i , j ) = g c d ( j , i ) gcd(i,j)=gcd(j,i) ,所以我们可以直接设 i j i\geq j ,然后乘上一个2,但是这样会多算一次 i = j = 1 i=j=1 的情况,所以要对方案数-1
p p r i m e ( i = 1 n p j = 1 i 2 [ g c d ( i , j ) = 1 ] 1 ) \sum_{p\in prime}( \sum_{i=1}^{\lfloor \frac np\rfloor}\sum_{j=1}^i2[gcd(i,j)=1]-1)

最后一个求和符号实际上就是 φ ( i ) \varphi(i) ,于是乎
p p r i m e ( i = 1 n p 2 φ ( i ) 1 ) \sum_{p\in prime}( \sum_{i=1}^{\lfloor \frac np\rfloor}2\varphi(i)-1)

这个时候我们直接用欧拉筛筛出素数,套进公式一看,发现复杂度是 O ( × n ) O(素数的个数\times n) ,好想会 T T ,咋办呢?

注意到第二个求和符号实际上是一个前缀和,所以我们设 s u m [ i ] = j = 1 i φ ( i ) sum[i]=\sum_{j=1}^i\varphi(i) ,就可以愉快 O ( n ) O(n)
p p r i m e ( s u m [ n p ] 1 ) \sum_{p\in prime}(sum[\lfloor \frac np\rfloor]-1)


C o d e   1 Code\ 1

#include<cstdio>
using namespace std;
const int N=1e7;
int n,phi[N+1],v[N+1],prime[N+1],m;
long long sum[N+1],ans;
signed main()
{
	scanf("%d",&n);
	phi[1]=1;sum[1]=1;
	for(register int i=2;i<=n;i++)
	{
		if(!v[i])
		{
			v[i]=i;prime[++m]=i;
			phi[i]=i-1;
		}
		for(register int j=1;j<=m;j++)
		{
			if(prime[j]>v[i]||prime[j]*i>n) break;
			v[i*prime[j]]=prime[j];
			phi[i*prime[j]]=phi[i]*(i%prime[j]?prime[j]-1:prime[j]);
		}
	}
	for(register int i=2;i<=n;i++) sum[i]=sum[i-1]+phi[i];
	for(register int i=1;i<=m;i++)
	{
		if(prime[i]>n) break;
		ans+=(sum[n/prime[i]]*2)-1;
	}
	printf("%lld",ans);
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/88849090
今日推荐