筛法,欧拉函数,递推(帮帮Tomisu,uva 11440)

本文介绍了一种利用欧拉函数计算小于特定数值M!并与之互质的数的数量的方法。通过判断一个数是否为素数来更新欧拉函数,并采用递推的方式进行计算。适用于解决数学问题和编程竞赛中的特定类型问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

x的所有素因子都大于M     ==>     x与M!互质。

若x>M!,那么x与M!互质     ==>     x%(M!)与M!互质。

因为M<=N,所以N!是M!的倍数,即M!能整除N!。那么我们只要算出小于M!的数中与M!互素的个数。然后乘以N!/M!就是答案。

如何求M!的欧拉函数呢?用递推的方法。

phi[i]表示i!的欧拉函数。


phi[1]=phi[2]=1;
    for(ll i=3;i<=n;i++)
        if(vis[i]) phi[i]=phi[i-1]*i%mod;
        else phi[i]=phi[i-1]*(i-1)%mod;

如果是i不是素数,那么
phi[i]=phi[i-1]*i%mod;
因为此时i!和(i-1)!的素因子集合完全相同。根据φ(n)=n(1-1/p1)(1-1/p2)...(1-1/pk)。乘一个i就好了。

如果i是素数,那么

phi[i]=phi[i-1]*(i-1)%mod;
根据公式,要乘以i*(1-1/i)=i-1。

最后答案要减1,因为从2开始算。


代码

#include<bits/stdc++.h>
#define maxn 10000010
using namespace std;
typedef long long ll;

const ll mod=100000007;

ll N,M;
bool vis[maxn];
ll phi[maxn];

void init()
{
    ll n=10000000;
    ll m=sqrt(n+0.5);
    for(ll i=2;i<=m;i++)
        if(!vis[i])
            for(ll j=i*i;j<=n;j+=i)
                vis[j]=true;
    phi[1]=phi[2]=1;
    for(ll i=3;i<=n;i++)
        if(vis[i]) phi[i]=phi[i-1]*i%mod;
        else phi[i]=phi[i-1]*(i-1)%mod;
}

int main()
{
    init();
    while(scanf("%lld %lld",&N,&M)==2&&(N+M))
    {
        ll ans=phi[M];
        for(ll i=M+1;i<=N;i++) ans=(ans*i)%mod;
        printf("%lld\n",(ans-1+mod)%mod);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值