欧拉函数

欧拉函数的定义:

   在数论中,对于正整数N,少于或等于N ([1,N]),且与N互质的正整数(包括1)的个数,记作φ(n)。

    φ函数的值:

   φ(x)=x(1-1/p(1))(1-1/p(2))(1-1/p(3))(1-1/p(4))…..(1-1/p(n)) 其中p(1),p(2)…p(n)为x

的所有质因数;x是正整数; φ(1)=1(唯一和1互质的数,且小于等于1)。注意:每种质因数只有一个。

     例如:

         φ(10)=10×(1-1/2)×(1-1/5)=4;

         1 3 7 9

         φ(30)=30×(1-1/2)×(1-1/3)×(1-1/5)=8;

         φ(49)=49×(1-1/7)=42;

相关拓展:给出一个N,求1..N中与N互质的数的和

ifgcd(n,i)=1 then gcd(n,n-i)=1 (1<=i<=n)

反证法:

        如果存在K!=1使gcd(n,n-i)=k,那么(n-i)%k==0

        而n%k=0

        那么必须保证i%k=0

        k是n的因子,如果i%k=0那么 gcd(n,i)=k,矛盾出现;

        于是问题变的非常简单: ANS=N*phi(N)/2

        i,n-i总是成对出现,并且和是n

       于是可能就有人问了,如果存在n-i=i那不是重复计算?

        答案是不会

        因为:

                n=2*i->i=n/2

1.如果n是奇数,那么n!=2*i,自然也不存在 n-i=i和重复计算之说

2.如果n是偶数,n=2*i成立,gcd(n,n/2)必然为n的一个因子,这个因子为1当且仅当n==2

3.于是对于n>2的偶数,绝对不存在gcd(n,n/2)=1所以更别说什么重复计算了

        对于n==2

        ans=2*1/2=1,正好也满足

        所以得到最终公式:

                  ans=N*phi(N)/2 


代码模板:

int euler(int n)
{
	int ans = n;
	for(int 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;
}

相关例题:      

一、

V - 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与n的最大公约数大于等于m

思路:设x = a*b,n = a*d(b与d互质且b <= d),此时gcd(x,n)便是a了。若要符合题意,则a >= m。如此,我们便只需要枚举a,计算1---d(也就是n/a)中有多少个整数与d互质,也就是求欧拉函数(d),所求和相加即为答案。

以下是AC代码:

#include <cstdio>  
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <list>
#include <map>
#include <stack>
#include <queue>
using namespace std;
#define ll long long
int euler(int n)
{
	int ans = n;
	for(int 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 t;
	while(cin >> t)
	{
		while(d)
		{
			int ans = 0;
			int n,m;
			cin >> n >> m;
			for(int i = 1;i*i <= n;i++)
				if(n%i == 0)
				{
					if(i >= m && i*i != n)//i*i != n防止当等于n时计算两次
						ans+=euler(n/i);
					if(n/i >= m )
						ans+=euler(i);
				}
			cout << ans <<endl;
		}
	}
	//cout << "AC" <<endl;
	return 0;
}

二、

Calculation 2
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Description

Given a positive integer N, your task is to calculate the sum of the positive integers less than N which are not coprime to N. A is said to be coprime to B if A, B share no common positive divisors except 1.
 

Input

For each test case, there is a line containing a positive integer N(1 ≤ N ≤ 1000000000). A line containing a single 0 follows the last test case.
 

Output

For each test case, you should print the sum module 1000000007 in a line.
 

Sample Input

340
 

Sample Output

02


大意:给出一个整数n,在1到n-1中找出与n不互质的整数的和。

思路:需要用到上面相关拓展的知识点,求出1到n-1的整数的和,并减去1到n-1中与n互质的整数的和即可

附上AC代码:

#include <cstdio>  
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <list>
#include <map>
#include <stack>
#include <queue>
using namespace std;
#define ll long long
ll euler(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()
{
	ll n;
	while(cin >> n && n)
		cout << (n*(n-1)/2 - euler(n)*n/2)%1000000007 <<endl;
	//cout << "AC" <<endl;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值