Phi的反函数

P4780 Phi 的反函数

update 2023/2/17 作者笔误

φ 定义

φ(n) 代表从 1n 所有与 n 互质的数的个数。

 φ(n) 

普通求法:

首先将 n 唯一分解为:

n=x1p1×x2p2×xnpn

φ(n)=n×(11x1)×(11x2)××(11xn)

证明:

首先我们考虑在所有数中有 1x 的概率会取到一个数是 x 的倍数,那么有 (11x) 的概率会取到一个数不是 x 的倍数, 1nn 个数,我们要找到 1n 所有与 n 互质的数,也就是去一个不是 n 的任意一个因数 (x1,x2,x3xn) 的倍数,就得到以上式子。

两个定理:

1.{φ(nm)=φ(n)×φ(m)     gcd(n,m)=1φ(nm)=φ(n)×m           gcd(n,m)=m

定理 1 证明:

gcd(n,m)=1 情况下可以推导:

n=x1p1×x2p2×xnpn

m=y1q1×y2q2×ynqn

n×m=x1p1×x2p2×xnpn×y1q1×y2q2×ynqn

φ(nm)=n×m×(11x1)×(11xn)×(11y1)×(11yn)=φ(n)×φ(m)            gcd(n,m)=1

  1. gcd(n,m)=m 情况下

考虑感性理解, 1n 里面有 φ(n) 个与 n 互质,那么扩大 m 倍,相当于有 m1n 就直接乘(因为我们保证了 gcd(n,m)=m 也就是 nm 的倍数,所以不存在乘上 m 后多出了不属于 n 的因子)。

定理 2.φ(n)=n1             nprim(这显而易见)

我们需要求 Phi 的反函数就要先深刻理解上述内容然后进行运用

可以根据上述定理 1 得到:

(在这里我们用到了定理一第一类和定理一第二类的一种特殊情况  φ(n×n)=φ(n)×n 

得出
 φ(x)=φ(a1)×a1p11×φ(a2)×a2p21×......φ(an)×anpn1                  aiprime

由定理二得: ai 都是质数,所以 φ(ai)=ai1

所有质数分解出来不超过 10 个,因为2×3×5×7×11×13×17×19×23×29=6469693230

                                   231=2147483648

所以可以直接暴力搜索。

(关于判断是否为质数的函数)

因为数据范围在 231 ,如果我们求 231 范围内的质数,直接爆炸,

其实我们只需要找出 216 的质数,每次判断一下当前这个数 now+1 (也就是 revphi(now) 是不是质数

例如 φ(x)=n=φ(3)×φ(10000000007)

第一次找到 φ(3) 处理以后,由于我们只找了 216 的质数,我们找不到 φ(1000000007) 在里面,我们需要每次判断当前这是数是不是质数。

具体的:

第一次判断 φ(3)×φ(1000000007) 显然不是质数。

除以 φ(3) 后变成了 φ(1000000007) 也就是 now=1e9+6

第二次判断 (now+1)prime 那么直接把质数给除了,直接结束了。

那么怎么得出答案呢

1.{φ(nm)=φ(n)×φ(m)     gcd(n,m)=1φ(nm)=φ(n)×m           gcd(n,m)=m

φ(x)=φ(a1)×a1p11×φ(a2)×a2p21×......φ(an)×anpn1                  aiprime

我们再来重新看看这些式子:

可以看出最后的 ans=a1×a1p11×a2×a2p21×......×an×anpn1 

代码:

#include<bits/stdc++.h> 
#define ll long long 
using namespace std;
const int N=1e7+10;
int vis[N],s[30],tot=0,n,cnt=0;
ll ans=1e17+10,prim[N];
void shai(int x){
    for(int i=2;i<=x;i++){
        if(!vis[i]){
            prim[++tot]=i;
        }
        for(int j=1;j<=tot&&i*prim[j]<=x;j++){
            vis[prim[j]*i]=1;
            if(!i%prim[j]){
                break;
            }
        }
    }    
}//质数筛
bool is_p(ll x){
    for(int i=2;i* i<=x;i++){
        if(x%i==0){
            //cout<<x<<i<<endl;
            return 0;
        }
    }
    return 1;
}//判断是否为质数
void dfs(int now,int id,ll rev){//id代表当前干过的质数,是个优化
    if(now>=ans) return ;//简单优化
    if(now==1){
        ans=min(rev,ans);
        return ;
    }
    if(is_p(now+1)) dfs(1,id+1,rev*(now+1));
    for(int i=id;i<=tot;i++){
        if(now%(prim[i]-1)==0){
            int a=now;
            ll b=rev;
            a/=(prim[i]-1);b*=prim[i]; //定理1的情况1
            dfs(a,i+1,b);
            while(a%prim[i]==0){//定理1的情况2
                a/=prim[i];b*=prim[i]; 
                dfs(a,i,b);
            } 
        }
    }
}

int main(){
    scanf("%d",&n);
    shai(sqrt(n)+1);    
    dfs(n,1,1);
    if(ans==1e17+10){//无解或者太大了
        printf("-1");
    }else printf("%lld",ans);
    return 0;
}
//2147483647
posted @   He_Zi  阅读(136)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示