杭电1286——欧拉函数——找新朋友

`

杭电1286——欧拉函数——找新朋友

新年快到了,“猪头帮协会”准备搞一个聚会,已经知道现有会员N人,把会员从1到N编号,其中会长的号码是N号,凡是和会长是老朋友的,那么该会员的号码肯定和N有大于1的公约数,否则都是新朋友,现在会长想知道究竟有几个新朋友?请你编程序帮会长计算出来。
Input
第一行是测试数据的组数CN(Case number,1<CN<10000),接着有CN行正整数N(1<n<32768),表示会员人数。
Output
对于每一个N,输出一行新朋友的人数,这样共有CN行输出。

Sample Input
2
25608
24027
Sample Output
7680
16016

补充欧拉函数:
在数论,对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目.如:φ(1)=1 此函数以其首名研究者欧拉命名(Euler’s totient function),它又称为Euler’s totient function、φ函数、欧拉商数等。 例如φ(8)=4,因为1,3,5,7均和8互质
互质:
互质是公约数只有1的两个整数,叫做互质整数。

看到这有没有发现 题目的意思就是让我们求 1——n-1 中与 n 互质的数的总数,自然就转化为求 φ(n)的值。

欧拉函数的C语言代码:
以两个等式为基础编写的代码
N = P1 ^ q1 * P2 ^ q2 * … * Pn ^ qn.
φ(N) = N * (1-1/P1) * (1-1/P2) * … * (1-1/Pn)

只和底数有关,和指数无关

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

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

8 = 2^3
ψ(8)=8×(1-1/2 ) =4;

#include<stdio.h>
#include<stdlib.h>
int eular(int n)
{
    int ans = n;
    int i;
    for (i=2;i<=sqrt(n);i++)		//找第一个因数
    {
        if (n % i == 0)	//如果为因数  i
        {
            ans = ans * (i - 1) / i;
            while (n % i == 0)		//去  因数 i 的指数,直到 i 不为 更新后 n 的因数 
                n = n / i;
        }
    }
    if (n > 1)	//最后一个因数(也是最大的因数) 可能不符合循环条件而跳出循环,这里将其捕获。
        ans = ans * (n - 1) / n;
    return ans;
}
int main ()
{ 
     int n,s;
     scanf("%d",&n);   
     s=eular(n);   
     printf("%d",s);   
     return 0;
}
``

解题代码一
欧拉函数

#include<stdio.h>
#include <iostream>
#include <algorithm>
#include<string.h>
#include<math.h>
int eular(int n)
{
    int ans = n;
    int i;
    for (i=2;i<=sqrt(n);i++)
    {
        if (n % i == 0)
        {
            ans = ans * (i - 1) / i;
            while (n % i == 0)
                n = n / i;
        }
    }
    if (n > 1)
        ans = ans * (n - 1) / n;
    return ans;
}
int main()
{
    int n,CN;
    scanf("%d",&CN);
    while (CN--)
    {
        scanf("%d",&n);
        printf("%d\n",eular(n));
    }
    return 0;
}

解题代码二:
用空间换时间

#include<stdio.h>
#include <iostream>
#include <algorithm>
#include<string.h>
#include<math.h>
int a[33000];		//定义一个很大的数组
using namespace std;
int main()
{
    int n,CN;
    scanf("%d",&CN);
    while (CN--)
    {
        scanf("%d",&n);
        memset(a,0,sizeof(a));	//数组初始化为 0 
        int i;
        int sum = 0;
        for (i=2;i<=n/2;i++)		//循环求 n 的因数
        {
            int k = 1;
            while (n % i == 0 && k * i <= n)	//由于 i 为 n 的因数,所以 i 的 k 倍 为老朋友.循环求出所以符合条件的下标 并赋值 1 。(这是解题的核心,极大的减少了时间的消耗)
            {
                a[k*i] = 1;	//老朋友为 1 ,新朋友 为 0
                k++;
            }
        }
        for (i=1;i<n;i++)	//输出
        {
            if (a[i] == 0)
                sum++;
        }
        printf("%d\n",sum);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43557810/article/details/87477494