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

来源:互联网 发布:js 设置css 编辑:程序博客网 时间:2024/05/01 10:02

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 10000010using 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;}


0 0
原创粉丝点击