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

来源:互联网 发布:西安软件公寓地址 编辑:程序博客网 时间:2024/05/21 11:01

题目链接: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 1000000007LL 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;}



0 0
原创粉丝点击