UVa 11440 Help Tomisu (欧拉函数)

题目

题目大意

给定正整数\(N\)\(M\), 统计\(2\)\(N!\)之间有多少个整数\(x\)满足: \(x\)的所有素因子都大于\(M\)(\(2 ≤ N ≤ 10^7\), \(1 ≤ M ≤ N\), \(N - M ≤ 10^5\))。输出答案除以\(100000007\)的余数。例如, \(N = 100\), \(M = 10\)时的答案为\(43274465\)

题解

因为\(M ≤ N\), 所以\(N!\)\(M!\)的整数倍。所有素因子都大于\(M\)等价于和\(M!\)互质。根据最大公约数的性质, 对于\(k > M!\), \(k\)\(M!\)互质当且仅当\(k\ mod\ M!\)\(M!\)互质。这样就只需要求出不超过\(M!\)且与\(M!\)互质的正整数个数, 再乘以\(\frac{N!}{M!}\)即可。

根据欧拉函数的公式:

\[\phi(n) = n(1 - \frac{1}{p_1})(1 - \frac{1}{p_2})\cdots(1 - \frac{1}{p_k})\]

如果\(n\)不是质数, 那么\(n!\)\((n - 1)!\)的质因子集合相同, 因此\(phifac(n) = n\ phifac(n - 1)\); 如果\(n\)是质数, 那么还会多一项\((1 - \frac{1}{n})\), 即\(phifac(n) = (n - 1)\ phifac(n - 1)\)

代码
#include <cstdio>
#include <cstring>
const long long kMod(100000007);
long long phifac[10000010] = {0, 1, 1};
bool mark[10000010];
long long n, m;
long long ans;
int main(int argc, char const *argv[]) {
  memset(mark, true, sizeof(mark));
  mark[0] = mark[1] = false;
  for (register int i(2); i <= 10000000; ++i) {
    if (mark[i]) {
      for (register int j(2); i * j <= 10000000; ++j) {
        mark[i * j] = false;
      }
    }
  }
  for (register long long i(3); i <= 10000000; ++i) {
    phifac[i] = phifac[i - 1] * (mark[i] ? i - 1 : i) % kMod;
  }
  while (~scanf("%lld %lld", &n, &m) && (n || m)) {
    ans = phifac[m];
    for (register long long i(m + 1); i <= n; ++i) ans = ans * i % kMod;
    printf("%lld\n", (ans - 1 + kMod) % kMod);
  }
  return 0;
}

转载于:https://www.cnblogs.com/forth/p/9724751.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值