【欧拉函数打表】LightOJ - 1370 Bi-shoe and Phi-shoe

Problem Description

给出一些数字,对于每个数字找到一个欧拉函数值大于等于这个数的数,求找到的所有数的最小和。f(n)的n至少从2开始。

思路:

欧拉函数f(n)定义:表示小于或等于n的数中与n互质的数的数目,f(n) = n∏(1 - 1/p)其中p|n

欧拉函数求值的方法
(1) f(1) = 1;
(2) 若n是素数p的k次幂,f(n) = p^k - p^(k-1) = (p - 1)*p^(k - 1);
(3) 若m, n互质,f(n*m) = f(n) * f(m);
n为奇数时,f(2*n) = f(2) * f(n) = f(n)。n为质素时,f(n) = n - 1。
欧拉定理。设gcd(a, m) = 1, 则a^(f(m)) = 1(mod)m。

费马小定理。对任意a和任意质数p有,a^p ≡ a(mod)p。当gcd(a, p)=1时,由欧拉定理进一步得到a^(p - 1) ≡ 1(mod)p。

根据欧拉函数的定义,可以推出欧拉函数的递推式
令p为N的最小质因数,若p^2|N, f(n) = f(n/p) * p; 否则f(n) = f(n / p) * (p - 1);
感性证明下:若 p^2|N, 与 n/p 互质的数 + p 的倍数 和 n 也是互质的;否则 gcd(n/p, p) = 1;

这题就是打一个欧拉函数的表,然后跑就可以了,所以主要用到递推式

#include<bits/stdc++.h>
using namespace std;
const int N = 1111110;
int minDiv[N], phi[N];//minDiv[i]用来存i的最小质因数,phi[i]就是欧拉函数
int a[10055];
void genPhi()//打欧拉函数表
{
    for(int i = 1; i < N; i++){//初始化
        minDiv[i] = i;
    }
    for(int i = 2; i*i < N; i++)
    {
        if(minDiv[i] == i){//i为质素
            for(int j = i*i; j < N; j += i){//更新后面的j的最小质因数
                minDiv[j] = i;
            }
        }
    }
    phi[1] = 1;//1的欧拉函数为1
    for(int i = 2; i < N; i++)
    {
        phi[i] = phi[i / minDiv[i]];
        if((i / minDiv[i]) % minDiv[i] == 0){//minDiv[i]^2|N
            phi[i] *= minDiv[i];
        }else{
            phi[i] *= minDiv[i] - 1;
        }
    }
}
int main()
{
    int T, Case = 1, n, i, x;
    genPhi();
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        for(i = 0; i < n; i++)
            scanf("%d", &a[i]);
        long long ans = 0;
        for(i = 0; i < n; i++)
        {
            x = a[i] + 1;//i肯定大于phi[i]所以,直接从a[i]的后一位开始找
            while(phi[x] < a[i]){
                x++;
            }
            ans += (long long)x;
        }
        printf("Case %d: %lld Xukha\n", Case++, ans);
    }
    return 0;
}

使用欧拉函数f(n)定义:表示小于或等于n的数中与n互质的数的数目,f(n) = n∏(1 - 1/p)其中p|n 打的表,我们可以在筛素数p的过程中,不断更新素数的倍数x*p*(1-1/p)。这样素数筛完,欧拉函数表也打出来了

#include<bits/stdc++.h>
using namespace std;
const int N = 1111110;
int phi[N];//minDiv[i]用来存i的最小质因数,phi[i]就是欧拉函数
int a[10055];
void genPhi()//打欧拉函数表
{
    int i, j;
    for(i = 0; i < N; i++)
        phi[i] = i;
    for(i = 2; i < N; i++)
    {
        if(phi[i] == i)
        {
            for(j = i; j < N; j += i)
                phi[j] = phi[j]/i * (i - 1);//先除在乘
        }
    }
}
int main()
{
    int T, Case = 1, n, i, x;
    genPhi();
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        for(i = 0; i < n; i++)
            scanf("%d", &a[i]);
        long long ans = 0;
        for(i = 0; i < n; i++)
        {
            x = a[i] + 1;//i肯定大于phi[i]所以,直接从a[i]的后一位开始找
            while(phi[x] < a[i]){
                x++;
            }
            ans += (long long)x;
        }
        printf("Case %d: %lld Xukha\n", Case++, ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值