C++數論—————彈藥科技

題目描述:

經過精靈族全力抵擋,精靈終於堅持到了聯絡系統的重建,於是精靈向人類求助,
大魔法師伊扎洛決定弓}用博士的最新科技來抗敵。
伊扎洛:“博士,還沒好嗎?”
博士:“只差一步了!只需要在正確的位置裝上彈藥就可以了!”
博士的最新科技是全新的炸彈,但是現在還需要一步裝彈藥的操作。博士的炸彈有
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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章