HDU 5407 CRB and Candies (2015多校第10場第一題)素數打表,除法取模(乘法逆元)

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=5407

題意:求N個不同的糖果吃K個的所有情況的最小公倍數,並取模

思路:簡單一推,就知道結果爲n的所有排列的LCM,但是直接這樣做的話一定超時,所以得換種方式,因爲每個n都有唯一解,所以求助於OEIS http://oeis.org/?language=english ,將給出的案例一一輸入可得



這樣就有了公式 LCM{1,2,...,n} / n. 再求出LCM{1,2,...,n} 



其中這個公式爲

所以之後我們就知道了先要打一個1~10^6的素數表,再打出所有的素數的多次方,但是因爲有除法取模所以要求逆元

代碼:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL __int64
#define N 1000005
#define mod 1000000007

LL f[N];
bool isPrime[N];
int total;//計數
int prime[79000];
int vis[N];
void getPrime()
{
    total=0;
    memset(isPrime,true,sizeof(isPrime));
    memset(prime,0,sizeof(prime));
    memset(vis,0,sizeof(vis));
    for(int i=2; i<=N-5; i++)
    {
        if(isPrime[i]) prime[total++]=i;
        for(int j=0; j<total && i*prime[j]<=N-5; j++)
        {
            isPrime[i*prime[j]]=false;
            if(i%prime[j]==0)
                break;
        }
    }
    for(int i=0; i<total; i++)
    {
        LL a=prime[i];
        LL b=a;
        for(; a<N; a*=b)
        {
            vis[a]=b;
        }
    }
}

void init()
{
    getPrime();
    f[1]=1;
    for(int i=2; i<=N-4; i++)
    {
        if(vis[i])
            f[i]=f[i-1]*vis[i]%mod;
        else
            f[i]=f[i-1];
        f[i]%=mod;
    }
}
LL extend_gcd(LL a,LL b,LL &x,LL &y)
{
    if(a==0&&b==0) return -1;//無最大公約數
    if(b==0){x=1;y=0;return a;}
    LL d=extend_gcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}
//*********求逆元素*******************
//ax = 1(mod n)
LL mod_reverse(LL a,LL n)
{
    LL x,y;
    LL d=extend_gcd(a,n,x,y);
    if(d==1) return (x%n+n)%n;
    else return -1;
}

int main()
{
    init();
    int t,n,i,j;
    while(scanf("%d",&t)==1)
    {
        while(t--)
        {
            scanf("%d",&n);
            LL ni=mod_reverse(n+1,mod);
            printf("%I64d\n",f[n+1]*ni%mod);
        }
    }
    return 0;
}



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