数论 - 分解质因数+欧拉函数 - Relatives POJ - 2407

数论 - 分解质因数+欧拉函数

文章目录

    • 数论 - 分解质因数+欧拉函数
      • 一、分解质因数
      • 二、欧拉函数
      • 三、模板: Relatives POJ - 2407

一、分解质因数

由 算 术 基 本 定 理 , 任 何 一 个 大 于 1 的 自 然 数 N , 如 果 N 不 为 质 数 , 那 么 N 可 以 唯 一 分 解 成 有 限 个 质 数 的 乘 积 N = P 1 a 1 P 2 a 2 P 3 a 3 . . . . . . P n a n , 这 里 P 1 < P 2 < P 3 . . . . . . < P n 均 为 质 数 , 其 中 指 数 a i 是 正 整 数 。   现 给 定 一 个 正 整 数 n , 可 以 以 小 于 O ( n ) 的 时 间 复 杂 度 得 到 其 所 有 的 质 因 子 及 每 个 质 因 子 对 应 的 幂 。 即 得 到 P 1 , P 2 , . . . , P n 和 a 1 , a 2 , . . . , a n 。   同 质 数 判 定 的 方 法 类 似 , 需 要 另 外 注 意 两 点 : ① 、 依 然 是 i 从 2 开 始 枚 举 每 个 质 因 子 , 每 次 枚 举 到 一 个 质 因 子 就 从 n 中 把 i 除 尽 , 这 样 可 以 保 证 合 数 因 子 被 除 掉 。   ② 、 对 任 意 的 n , 至 多 仅 有 一 个 大 于 n 的 质 因 子 。 因 为 显 然 假 设 大 于 n 的 质 因 子 数 量 大 于 等 于 2 , 那 么 这 两 个 质 因 子 乘 积 必 然 大 于 n 。   有 了 上 面 这 个 性 质 , 我 们 每 次 枚 举 质 因 子 i , 只 需 要 循 环 到 n i 次 即 可 , 若 最 后 n > 1 , 说 明 存 在 一 个 比 n 大 的 质 因 子 , 就 是 此 时 的 “ n ” 。 由 于 每 次 枚 举 一 个 i , 会 把 n 中 的 i 因 子 除 尽 , 总 的 时 间 复 杂 度 是 介 于 O ( l o g 2 n ) − O ( n ) 之 间 的 。 由算术基本定理,任何一个大于1的自然数 N,如果N不为质数,\\那么N可以唯一分解成有限个质数的乘积N=P_1^{a_1}P_2^{a_2}P_3^{a_3}......P_n^{a_n},\\这里P_11,说明存在一个比\sqrt{n}大的质因子,就是此时的“n”。\\由于每次枚举一个i,会把n中的i因子除尽,总的时间复杂度是介于O(log_2n)-O(\sqrt{n})之间的。 1NNNN=P1a1P2a2P3a3......PnanP1<P2<P3......<Pnai nO(n )P1,P2,...,Pna1,a2,...,an i2ni nn n 2n iinn>1n niniO(log2n)O(n )

例题:

给定n个正整数ai,将每个数分解质因数,并按照质因数从小到大的顺序输出每个质因数的底数和指数。

输入格式
第一行包含整数n。

接下来n行,每行包含一个正整数ai。

输出格式
对于每个正整数ai,按照从小到大的顺序输出其分解质因数后,每个质因数的底数和指数,每个底数和指数占一行。

每个正整数的质因数全部输出完毕后,输出一个空行。

数据范围
1≤n≤100,
1≤ai≤2∗109

输入样例:
2
6
8

输出样例:
2 1
3 1

2 3

代码:

#include 
#include 
#include 
#include 
using namespace std;

int n,x;
void divide(int x)
{
    for(int i=2;i<=x/i;i++)
        if(x%i==0)
        {
            int cnt=0;
            while(x%i==0)
            {
                x/=i;
                cnt++;
            }
            cout<<i<<" "<<cnt<<endl;
        }
    if(x>1) cout<<x<<" "<<1<<endl;
    cout<<endl;
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>x;
        divide(x);
    }
    return 0;
}

二、欧拉函数

对 于 正 整 数 n , 用 欧 拉 函 数 能 够 求 得 [ 1 , n − 1 ] 中 与 n 互 质 的 数 的 个 数 。   对 正 整 数 n = p 1 a 1 p 2 a 2 . . . p n a n , 欧 拉 函 数 ϕ ( n ) = n ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) . . . ( 1 − 1 p n ) , 其 中 , p 1 , p 2 , . . . , p n 是 n 的 质 因 子 。   原 理 : 直 白 地 讲 , p i 是 n 的 任 意 质 因 子 , 设 [ 1 , n ] 中 , 是 p i 的 倍 数 的 数 ( p i , 2 p i , . . . ) 的 个 数 是 a i ,   那 么 [ 1 , n − 1 ] 中 与 n 互 质 的 数 的 个 数 = n − ∑ a i , 而 a i = n p i , 借 助 容 斥 原 理 得 到 的 式 子 即 ϕ ( n ) 乘 积 展 开 的 式 子 。   求 正 整 数 n 的 欧 拉 函 数 , 我 们 可 以 利 用 分 解 质 因 数 的 方 法 求 得 n 的 所 有 质 因 子 , 再 代 入 公 式 即 可 。 时 间 复 杂 度 仍 然 是 小 于 O ( n ) 的 。 对于正整数n,用欧拉函数能够求得[1,n-1]中与n互质的数的个数。\\ \ \\对正整数n=p_1^{a_1}p_2^{a_2}...p_n^{a_n},欧拉函数\phi(n)=n(1-\frac{1}{p_1})(1-\frac{1}{p_2})...(1-\frac{1}{p_n}),其中,p_1,p_2,...,p_n是n的质因子。\\ \ \\原理:直白地讲,p_i是n的任意质因子,设[1,n]中,是p_i的倍数的数(p_i,2p_i,...)的个数是a_i,\\ \ \\那么[1,n-1]中与n互质的数的个数=n-\sum a_i,而a_i=\frac{n}{p_i},借助容斥原理得到的式子即\phi(n)乘积展开的式子。\\ \ \\求正整数n的欧拉函数,我们可以利用分解质因数的方法求得n的所有质因子,再代入公式即可。\\时间复杂度仍然是小于O(\sqrt{n})的。 n[1,n1]n n=p1a1p2a2...pnanϕ(n)=n(1p11)(1p21)...(1pn1),p1,p2,...,pnn pin[1,n]pi(pi,2pi,...)ai [1,n1]n=naiai=pinϕ(n) nnO(n )

例题:

给定n个正整数ai,请你求出每个数的欧拉函数。

输入格式
第一行包含整数n。

接下来n行,每行包含一个正整数ai。

输出格式
输出共n行,每行输出一个正整数ai的欧拉函数。

数据范围
1≤n≤100,
1≤ai≤2∗109

输入样例:
3
3
6
8
输出样例:
2
2
4

注意:

为 了 避 免 计 算 过 程 中 小 数 的 出 现 , 将 n ( 1 − 1 p i ) 转 化 为 n / p i × ( p i − 1 ) 。 为了避免计算过程中小数的出现,将n(1-\frac{1}{p_i})转化为n/p_i×(p_i-1)。 n(1pi1)n/pi×(pi1)


代码:

#include 
#include 
#include 
#include 
using namespace std;

int n,a;

int main()
{
    cin>>n;
    while(n--)
    {
        cin>>a;
        int ans=a;
        for(int i=2;i<=a/i;i++)
        {
            if(a%i==0)
            {
                ans=ans/i*(i-1);
                while(a%i==0) a/=i;
            }
        }
        if(a>1) ans=ans/a*(a-1);
        cout<<ans<<endl;
    }

    return 0;
}

三、模板: Relatives POJ - 2407

题意:

给 定 正 整 数 n , 输 出 [ 1 , n − 1 ] 内 , 与 n 互 质 的 数 的 个 数 。 0 为 输 入 结 尾 。 给定正整数n,输出[1,n-1]内,与n互质的数的个数。0为输入结尾。 n[1,n1]n0

Sample Input:
7
12
0

Sample Output:
6
4

数据范围:

n < = 1 0 9 , T i m e   l i m i t : 1000 m s , M e m o r y   l i m i t : 65536 k B n<=10^9,\\Time\ limit:1000 ms,Memory\ limit:65536 kB n<=109,Time limit1000msMemory limit65536kB


代码:

#include 
#include 
#include 
#include 
using namespace std;

int n;
int euler(int n)
{
    int res=n;
    for(int i=2;i<=n/i;i++)
    {
        if(n%i==0)
        {
            res=res/i*(i-1);
            while(n%i==0) n/=i;
        }
    }
    if(n>1) res=res/n*(n-1);
    return res;
}

int main()
{
    while(~scanf("%d",&n),n)
        printf("%d\n",euler(n));

    return 0;
}

你可能感兴趣的:(数论)