題目鏈接: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;
}