C++数论—————弹药科技

版权声明:蒟蒻原创博客,大佬转载也需附上链接: https://blog.csdn.net/weixin_43810158/article/details/89181406

题目描述:

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

输入:

一个数N(N <= 1000000)

输出:

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

输入样例:

4

输出样例:

9

思路分析:

这一道题我们先这样想,答案是不是就是N的阶乘减去gcd(i,N)和N! mod i ≠ 0的数的个数。

其实这一说法就是求它的因子和欧拉函数。

那么我们需要关注两个点:

一是欧拉函数

这一题的求解方法是用数的唯一分解和欧拉筛法所求的质数来求答案(若想要详解,请点击)。

二是因子数

刚才我们已经求出了w[i](所分质数的指数),那么因子数就是tot=tot*w[i]

而一算了两次我们要在最后在答案上加上1。

最后一点就是循环一定要用long long因为有一个循环的累乘会超int。

代码实现:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
#define MAXN 1000005
ll n,m,p1,p[MAXN],sumn=1,ans,tot=1,s[MAXN],phin=1,mod=1e9+7;
bool v[MAXN];
ll qkpow(ll x,ll y)
{
    ll ans=1;
    while(y>0)
    {
        if(y%2==1)
            ans=(ans*x)%mod;
        x=(x*x)%mod;
        y/=2;
    }
    return ans;
}
void olsf()
{
    for(ll i=2;i<=n;i++)
    {
        if(!v[i])
        {
            p1++;
            p[p1]=i;
        }
        for(ll j=1;j<=p1&&i*p[j]<=n;j++)
        {
            v[i*p[j]]=1;
            if(i%p[j]==0)
                break;
        }
    }
}
int main()
{
    scanf("%lld",&n);
    for(ll i=2;i<=n;i++)
        tot=(tot*i)%mod;
    olsf();
    for(ll i=1;i<=p1;i++)
        for(ll j=p[i];j<=n;j*=p[i])
            s[i]+=n/j;
    for(ll i=1;i<=p1;i++)
    {
        phin=((phin*qkpow(p[i],s[i]-1)%mod)*(p[i]-1))%mod;
        sumn=(sumn*(s[i]+1))%mod;
    }
    ans=(((((tot-phin)%mod+mod)%mod-sumn)%mod+mod)%mod+1)%mod;
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43810158/article/details/89181406
今日推荐