弹药科技



目录

一.题目

题目描述

输入

输出

样例输入

样例输出

提示

二.题解

三.代码

谢谢!


一.题目

题目描述

经过精灵族全力抵挡,精灵终于坚持到了联络系统的重建,于是精灵向人类求助,大魔法师伊扎洛决定弓}用博士的最新科技来抗敌。
伊扎洛:“博士,还没好吗?”
博士:“只差一步了!只需要在正确的位置装上弹药就可以了!”
博士的最新科技是全新的炸弹,但是现在还需要一步装弹药的操作。博士的炸弹有N!个位置可以装弹药(>.<),但是只有在正确的位置装上弹药才能启动,博士将装弹药的位置编号为1到N!,一个位置i需要装弹药,当且仅当gcd(i, N!) ≠ 1且N! mod i ≠ 0,现在博士不要求你求出所有装弹药位置,只需要你求出满足要求的位置的数量就可以了。

输入

一个数N

输出

表示满足要求的位置数量,答案对mod1000000007输出

样例输入

4

样例输出

9

提示

【数据范围】
N <= 1000000

二.题解

这道题其实已经很明显了,大家可以反着想,直接根据条件得出计算的公式:

从这个公式:gcd(i, N!) ≠ 1,我们可以得出,i和N!并不互质,所以减去与N!互质,且比N!小的数,就是欧拉函数。(命为x)

从这个公式:N! mod i ≠ 0,我们可以得出,i不是N!的因数,所以减去N!的所有因数。(命为y)

最后还要加一个1,因为1被减了两次。

所以ans=N!-x-y+1

令:n=p_{1}^{w_{1}}*p_{2}^{w_{2}}*p_{3}^{w_{3}}*...*p_{m}^{w_{m}}(分解质因数legendre

欧拉函数的求法:①\phi (n)=p_{1}^{w_{1}-1}(p_{1}-1)*p_{2}^{w_{2}-1}(p_{2}-1)*p_{3}^{w_{3}-1}(p_{3}-1)*...*p_{m}^{w_{m}-1}(p_{m}-1)

                             ②\phi (n)=n*\frac{p_{1}-1}{p_{1}}*\frac{p_{2}-1}{p_{2}}*\frac{p_{3}-1}{p_{3}}*...*\frac{p_{m}-1}{p_{m}}

因数个数的求法:s=(w_{1}+1)*(w_{2}+1)*(w_{3}+1)*...*(w_{m}+1)

三.代码

//注意多开long long
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define mod 1000000007
#define M 1000005
#define LL long long
LL n_jc = 1, phin = 1, sumn = 1, ans, s[M], n, prime[M], pn;
bool vis[M];
void seive (LL x){
    for (LL i = 2; i <= x; i ++){
        if (! vis[i])
            prime[++ pn] = i;
        for (LL j = 1; j <= pn && i * prime[j] <= x; j ++){
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0)
                break;
        }
    }
}
LL qkpow (LL x, LL y){
    LL sum = 1;
    while (y > 0){
        if (y % 2 == 1)
            sum = sum * x % mod;
        x = x * x % mod;
        y /= 2;
    }
    return sum;
}
int main (){
    scanf ("%lld", &n);
    seive (n);
    for (LL i = 1; i <= n; i ++)
        n_jc = n_jc * i % mod;
    for (LL j = 1; j <= pn; j ++)
        for (LL k = prime[j]; k <= n; k *= prime[j])
            s[j] += n / k;
    for (LL i = 1; i <= pn; i ++){
        phin = phin * qkpow (prime[i], s[i] - 1) % mod * (prime[i] - 1) % mod;
        sumn = sumn * (s[i] + 1) % mod;
    }
    ans = (((((n_jc - phin) % mod + mod) % mod - sumn) % mod + mod) % mod + 1) % mod;
    printf ("%lld\n", ans);
    return 0;
}
 

谢谢!

发布了61 篇原创文章 · 获赞 32 · 访问量 8366

猜你喜欢

转载自blog.csdn.net/weixin_43908980/article/details/89145149