【欧拉函数】(数论)

何为欧拉函数:

在1-N中与N互质的数的个数被称为欧拉函数,记为φ(N).

若在算术基本定理中,N=p1^c1*p2^c2*....pm^cm,则

φ(N)=N*(p1-1)/p1*(p2-1)/p2*****(pm-1)/pm=N*ㄇ质数p|N (1-1/p)

 

模板:求解单个数的欧拉函数计算式:

ll eluer(ll n)
{
	ll ans=n;
	
	for(ll i=2;i*i<=n;i++)
	{
		if(n%i==0)
		{
			ans=ans/i*(i-1);
			while(n%i==0)
				n/=i;
		}
	}
	if(n>1)
		ans=ans/n*(n-1);
	return ans;
}

关于欧拉函数的性质:

1.任意n>1,1-n中与n互质的数的和为  n* φ(N) /2;

2.若 a,b互质 ,则φ(ab)=φ(a)*φ(b);

   积性函数:若a,b互质时,有f(ab)=f(a)*f(b),那么称函数f为积性函数。

3.若f是积性函数,在算术借本定理中,n=∏(i=1-->m)pi^ci,则 f(n)=∏(i=1-->m)f(pi^ci);

4.若p|n且p^2| n ,则φ(n)=φ(n/p)*p;

5.若p|n但 p^2 |/  n, 则φ(n)=φ(n/p)*(p-1)

6.∑d|n φ(d) = n

 

以上就是欧拉函数的性质,下面看一些例题吧,(毕竟光说不练假把式!)

 

question1:

可见的点

在一个平面直角坐标系的第一象限内,如果一个点(x,y)与原点(0,0)的连线中没有通过其他任何点,则称该点在原点处是可见的。

例如,点(4,2)就是不可见的,因为它与原点的连线会通过点(2,1)。

部分可见点与原点的连线如下图所示:

3090_1.png

编写一个程序,计算给定整数N的情况下,满足0≤x,y≤N0≤x,y≤N的可见点(x,y)的数量(可见点不包括原点)。

输入格式

第一行包含整数C,表示共有C组测试数据。

每组测试数据占一行,包含一个整数N。

输出格式

每组测试数据的输出占据一行。

应包括:测试数据的编号(从1开始),该组测试数据对应的N以及可见点的数量。

同行数据之间用空格隔开。

数据范围

1≤N,C≤10001≤N,C≤1000

输入样例:

4
2
4
5
231

输出样例:

1 2 5
2 4 13
3 5 21
4 231 32549


解题报告:第一眼的思路就是双重循环去求解gcd为1的对数,确实是可以实现的,但是会超时,所以应该使用欧拉函数,很明显可以看出来(1,1) (1,0),(0,1) 这三个点是一定会看到的,那么剩下的就是需要咱们去看的了,这个时候咱们可以只求解y=x一侧的点对数目,因为他们是对称的,当跑到横坐标为x的时候,和这个横坐标gcd等于1的数目不就是x的欧拉函数值吗,所以就可以将双重for降到一重,最后的欧拉函数值累加后,乘2 + 3,就是最后的答案。

ac代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;

const int maxn=1100;
int phi[maxn];

void eluer()
{
	for(int i=2;i<maxn;i++)
	{
		if(!phi[i])
		{
			for(int j=i;j<maxn;j+=i)
			{
				if(!phi[j]) phi[j]=j;
				phi[j]=phi[j]/i*(i-1);
			}
		}
	}
}

int main()
{
	int t,n;
	eluer();
	cin>>t;
	int kase=0;
	while(t--)
	{
		int ans=0;
		cin>>n;
		for(int i=2;i<=n;i++)
			ans+=2*phi[i];
		ans+=3;
		cout<<++kase<<" "<<n<<" ";
		if(ans==0)
			cout<<"0"<<endl;
		else
			cout<<ans<<endl;
	} 
	return 0;
}

 

question2:

GCD

The greatest common divisor GCD(a,b) of two positive integers a and b,sometimes written (a,b),is the largest divisor common to a and b,For example,(1,2)=1,(12,18)=6. 
(a,b) can be easily found by the Euclidean algorithm. Now Carp is considering a little more difficult problem: 
Given integers N and M, how many integer X satisfies 1<=X<=N and (X,N)>=M.

Input

The first line of input is an integer T(T<=100) representing the number of test cases. The following T lines each contains two numbers N and M (2<=N<=1000000000, 1<=M<=N), representing a test case.

Output

For each test case,output the answer on a single line.

Sample Input

3
1 1
10 2
10000 72

Sample Output

1
6
260

 

解题报告:看了几个题解,总觉得没有把这道题目的精髓给讲明白,后来自己思考了好久,终于算是有些头绪了,给定n,m,要求解的是在1-n范围内寻找某一个数x,gcd(x,n) >= m. 队友说是欧拉函数,(哭泣,欧拉函数到底在什么时候去使用,还需要去继续研究),然后知道了使用欧拉函数,但是不知道应该去怎么使用啊,后来看了一下直系学长的博客,觉得讲的不错,但是还不够细腻。决定自己写一下:

首先除了n的因子外的数和n的gcd肯定都是1,所以符合题意的x肯定是n的某个因子的倍数,所以咱们去寻找一下n的所有的因子,假设存在一个因子p >= m ,那么咱们就去求解一下 (n/p)的欧拉函数值是多少,累加一下。(至于为什么要求(n/p)的欧拉函数 这是为了解决”冲突“ 对于n的因子p和一个与(n/p)不互素的k  k*p就会变成n的其他因子或其他因子的倍数 这里需要仔细想想

ac代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;


ll eluer(ll n)
{
	ll ans=n;
	
	for(ll i=2;i*i<=n;i++)
	{
		if(n%i==0)
		{
			ans=ans/i*(i-1);
			while(n%i==0)
				n/=i;
		}
	}
	if(n>1)
		ans=ans/n*(n-1);
	return ans;
}

int main()
{
	int n,m,t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		ll ans=0;
		for(int i=1;i*i<=n;i++)
		{
			if(n%i==0)
			{
				if(n/i>=m&&i*i!=n)
					ans+=eluer(i);
				if(i>=m)
					ans+=eluer(n/i);
			}
		}
		printf("%lld\n",ans);
	}
}

 

question3:

上帝与集合的正确用法

Description

根据一些书上的记载,上帝的一次失败的创世经历是这样的:

第一天, 上帝创造了一个世界的基本元素,称做“元”。

第二天, 上帝创造了一个新的元素,称作“α”。“α”被定义为“元”构成的集合。容易发现,一共有两种不同的“α”。

第三天, 上帝又创造了一个新的元素,称作“β”。“β”被定义为“α”构成的集合。容易发现,一共有四种不同的“β”。

第四天, 上帝创造了新的元素“γ”,“γ”被定义为“β”的集合。显然,一共会有16种不同的“γ”。

如果按照这样下去,上帝创造的第四种元素将会有65536种,第五种元素将会有2^65536种。这将会是一个天文数字。

然而,上帝并没有预料到元素种类数的增长是如此的迅速。他想要让世界的元素丰富起来,因此,日复一日,年复一年,他重复地创造着新的元素……

然而不久,当上帝创造出最后一种元素“θ”时,他发现这世界的元素实在是太多了,以致于世界的容量不足,无法承受。因此在这一天,上帝毁灭了世界。

至今,上帝仍记得那次失败的创世经历,现在他想问问你,他最后一次创造的元素“θ”一共有多少种?

上帝觉得这个数字可能过于巨大而无法表示出来,因此你只需要回答这个数对p取模后的值即可。

你可以认为上帝从“α”到“θ”一共创造了10^9次元素,或10^18次,或者干脆∞次。

一句话题意:

 

Input

接下来T行,每行一个正整数p,代表你需要取模的值

 

Output

T行,每行一个正整数,为答案对p取模后的值

 

Sample Input

3
2
3
6

Sample Output

0
1
4

解题报告:就是一道看起来很玄乎的题目,因为2的幂次是没有结束的时候,但是咱们可以通过递归和欧拉降幂来将模数变为1,那么所有的数在模后就是0,这就是递归出口,要知道欧拉降幂的原则:

 

ac代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;

ll p;
int t;

ll phi(ll x)
{
	ll res=x;
	for(int i=2;i*i<=x;i++)
	{
		if(x%i==0)
		{
			res=res/i*(i-1);
			while(x%i==0)
				x/=i;
		}
	}
	if(x>1)
		res=res/x*(x-1);
	return res;
}
ll ksm(ll a,ll b,ll c)
{
	ll res=1;
	while(b)
	{
		if(b&1)
		{
			res=(res*a)%c;
		}
		a=(a*a)%c;
		b>>=1;
	}
	return res;
}
ll slove(ll x)
{
	if(x==1)
		return 0;
	return ksm(2,slove(phi(x))+phi(x),x);
}
int main()
{
	cin>>t;
	while(t--)
	{
		cin>>p;
		cout<<slove(p)<<endl;	
	}	
}

 

以上就是欧拉函数比较常用的几个应用,以后会慢慢补更多的!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值