欧拉函数的定义:
在数论中,对于正整数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
(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 72Sample 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;
}
二、
Description
Input
Output
Sample Input
Sample Output
大意:给出一个整数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;
}