首页 > 代码库 > Help Tomisu UVA - 11440 难推导+欧拉函数,给定正整数N和M, 统计2和N!之间有多少个整数x满足,x的所有素因子都大于M (2<=N<=1e7, 1<=M<=N, N-M<=1E5) 输出答案除以1e8+7的余数。

Help Tomisu UVA - 11440 难推导+欧拉函数,给定正整数N和M, 统计2和N!之间有多少个整数x满足,x的所有素因子都大于M (2<=N<=1e7, 1<=M<=N, N-M<=1E5) 输出答案除以1e8+7的余数。

/**
题目:Help Tomisu UVA - 11440
链接:https://vjudge.net/problem/UVA-11440
题意:给定正整数N和M, 统计2和N!之间有多少个整数x满足,x的所有素因子都大于M (2<=N<=1e7, 1<=M<=N, N-M<=1E5)
输出答案除以1e8+7的余数。
思路:
lrjP338

由于x的所有素因子都>M;那么x与M!互质。
根据最大公约数的性质,对于x>y,x与y互质,那么x%y与y也互质。
由于N>=M,那么N!%M!==0;
这样只需要求出M!内与M!互质的数的个数。再乘以N!/M!即为结果。
问题的重点在于求phi(M!);

根据欧拉函数公式:

phi(n) = n*(1-1/p1)*(1-1/p2)*...*(1-1/pk);

求phi(n!), 如果n为合数,那么phi(n!) = phi((n-1)!)*n;

如果n为素数,那么phi(n!) = phi((n-1)!)*n/(1-1/n) = phi((n-1)!)*(n-1);

phi(1) = phi(2) = 1;

设f(i) = phi(i!);

*/

#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e7+10;
const int mod = 1e8+7;
int f[maxn];
int prime[maxn];
void init()
{
    int N = sqrt(maxn+0.5);
    memset(prime, 0, sizeof prime);
    for(int i = 2; i<=N; i++){
        if(prime[i]==0){
            for(int j = i*i; j < maxn; j+=i){
                prime[j] = 1;
            }
        }
    }
    ///prime[i]==0; is prime;
    f[1] = f[2] = 1;
    for(int i = 3; i < maxn; i++){
        f[i] = 1LL*f[i-1]*(prime[i]==0?(i-1):i)%mod;
    }
}
int main()
{
    int n, m;
    init();
    while(scanf("%d%d",&n,&m)==2)
    {
        if(n==0&&m==0) break;
        ll ans = f[m];
        for(int i = m+1; i <= n; i++){
            ans = ans*i%mod;
        }
        printf("%lld\n",(ans-1+mod)%mod);
    }
    return 0;
}

 

Help Tomisu UVA - 11440 难推导+欧拉函数,给定正整数N和M, 统计2和N!之间有多少个整数x满足,x的所有素因子都大于M (2<=N<=1e7, 1<=M<=N, N-M<=1E5) 输出答案除以1e8+7的余数。