欧拉函数学习笔记

读前警告:本文 MD 以及 \(\LaTeX\) 差到爆炸,因为是直接复制的。

首先,\(\varphi(n)\) 的值是 \(n\) 内与 \(n\) 互质的数的个数。


//求n的欧拉函数值: phi[n]
int getPhi(int n){
    int ans = n;
    for(int i = 2; i*i <= n; i++){
        if(n % i == 0){
            ans = ans * (i-1)/i;
            while(n % i == 0) n /= i;
        }
    }
    if(n > 1) ans = ans * (n-1)/n ;
    return ans;
}
时间复杂度:sqrt(n)

你可能会问:你这玩意除了装X还有个【数据删除】用?

欸嘿还真不是,来了题你就知道了

T1

给定整数N和M,有多少整数X满足1<=X<=N且gcd(X,N)>=M?

第一行输入是一个整数T(T<=100),表示测试用例的数量。以下T行各包含两个数字N和M(2<=N<=100000000,1<=M<=N),表示一个测试用例。(注意这是个伏笔)


首先 \(N\) 最多有 \(\sqrt n\) 个因数(说实话大多数时间达不到这个上限)

\(d\)\(N\) 的约数,且 \(d>=M\)

其实它起的不是约数的作用,而是这个最大公因数!因为不管咋样 \(\gcd(N,X)\mid N\)

枚举它,问题就成了 \(1\)\(\frac{n}{d}\) 有多少数和 \(\frac{n}{d}\) 互质(\(\frac{n}{d}\)\(X\))。

欸这好像是 \(\varphi(\frac{n}{d})\) 欸!

然后就水了,直接求和。

对了记得伏笔吗?这个 \(\varphi\) 不能线性筛求,得用它自己的计算公式。

#include<stdio.h>
#include<bits/stdc++.h>
#define N 1000010
#define MOD 998244353
#define esp 1e-8
#define INF 999999999999999999
#define LL long long
#define rep(i,a,b,g) for(LL i=a;i<=b;i+=g)
#define rem(i,a,b,g) for(LL i=a;i>=b;i-=g)
#define repn(i,a,b,g) for(LL i=a;i<b;i+=g)
#define remn(i,a,b,g) for(LL i=a;i>b;i-=g)
#define pll pair<LL,LL>
#define mkp(x,y) make_pair(x,y)
#define lowbit(x) ((x)&(-(x)))
#define lc (u<<1)
#define rc (u<<1|1)
using namespace std;
LL phi(LL n)
{
	LL sum=n;
	for(LL i=2;i*i<=n;i++)
	{
		if(n%i==0)
		{
			sum=sum*(i-1)/i;
			while(n%i==0)n/=i;
		}
	}
	if(n>1)sum=sum*(n-1)/n;
	return sum;
}
LL t,n,m,p[100010],o;
int main()
{
	cin>>t;
	while(t--)
	{
		cin>>n>>m; 
		LL sum=0;
		o=0;
		for(LL i=1;i*i<n;i++)
		{
			if(n%i==0)
			{
				p[++o]=i;
				p[++o]=n/i;
			}
		}
		LL s=sqrt(n);
		if(s*s==n)p[++o]=s;
		rep(i,1,o,1)
		{
			if(p[i]>=m)sum+=phi(n/p[i]);
		}
		cout<<sum<<endl;
	}
	return 0;
}

T2

给定一个正整数N,你的任务是计算小于N且和N不互质的正整数的和。如果A,B除了1之外没有公共的正约数,则称A与B互质。


考虑补集,求出所有互质的数的总和。

利用欧拉函数和欧几里德定理,可知若 \(\gcd(n,i)=1\)\(\gcd(n,n-i)=1\)

于是乎所有与 \(n\) 互质的数的和为 \(\frac{n\times \varphi(n)}{2}\)(和为 \(n\),有 \(\frac{\varphi(n)}{2}\) 对)

那不互质的就是 \(\frac{n\times (n-1)-n\times \varphi(n)}{2}\)

#include<stdio.h>
#include<bits/stdc++.h>
#define MOD 1000000007
#define LL long long
using namespace std;
LL phi(LL n)
{
	LL sum=n;
	for(LL i=2;i*i<=n;i++)
	{
		if(n%i==0)
		{
			sum=sum*(i-1)/i;
			sum%=MOD;
			while(n%i==0)n/=i;
		}
	}
	if(n>1)sum=sum*(n-1)/n;
	sum%=MOD;
	return sum;
}
LL n;
int main()
{
	cin>>n;
	while(n!=0)
	{
		cout<<(n*(n-1)/2%MOD-phi(n)*n/2%MOD+MOD)%MOD<<endl;
		cin>>n;
	}
	return 0;
}

T3

洛谷P2303


暴力硬拆!!!!

爆枚 \(n\) 因数!!!

爆算 \(\varphi(\frac{n}{d})\)!!!!

#include<stdio.h>
#include<bits/stdc++.h>
#define N 1000010
#define MOD 998244353
#define esp 1e-8
#define INF 999999999999999999
#define LL long long
#define rep(i,a,b,g) for(LL i=a;i<=b;i+=g)
#define rem(i,a,b,g) for(LL i=a;i>=b;i-=g)
#define repn(i,a,b,g) for(LL i=a;i<b;i+=g)
#define remn(i,a,b,g) for(LL i=a;i>b;i-=g)
#define pll pair<LL,LL>
#define mkp(x,y) make_pair(x,y)
#define lowbit(x) ((x)&(-(x)))
#define lc (u<<1)
#define rc (u<<1|1)
using namespace std;
LL phi(LL n)
{
	LL sum=n;
	for(LL i=2;i*i<=n;i++)
	{
		if(n%i==0)
		{
			sum=sum*(i-1)/i;
			while(n%i==0)n/=i;
		}
	}
	if(n>1)sum=sum*(n-1)/n;
	return sum;
}
LL t,n;
int main()
{
	cin>>n; 
	LL sum=0;
	for(LL i=1;i*i<=n;i++)
	{
		if(n%i==0)
		{
			sum+=i*phi(n/i);
			if(i*i!=n)sum+=(n/i)*phi(i);
		}
	}
	cout<<sum<<endl;
	return 0;
}

热门相关:上古传人在都市   虎狼之师   盛华   最牛兵王   绝代疯少