题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5407
题意:
给定n,求C(n,0),C(n,1),...,C(n,n)的lcm(最小公倍数)对1e9+7取模的值。
分析:
C(n,k)中只包含不大于n的素因子,
对每个素因子p,需要找出这n个组合数中p的幂最大的,
由Kummer定理,
这相当于找一个k,使得在p进制下n-k发生借位的次数最多,
容易知道,在p进制下,
当n的某一位<p-1时,n的比这一位高的每一位都可以向下借位,
此时末尾是一串连续的p-1,
再用快速幂计算p对lcm的贡献即可,
需要先筛一遍不大于1e6的素数表,
总复杂度O(nloglogn+q*pi(n)*logn),
其中pi(n)=O(n/logn)是素数计数函数,
那么总复杂度也就是O(nloglogn+qn)。
补充:
有关Kummer定理可以参考
ZOJ 3842 Cirno's Perfect Math Class (Kummer定理) - quailty's - 博客频道 - CSDN.NET
代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const ll Mod=1000000007LL; const int MAXN=1000005; int cnt,p[80005]; bool np[MAXN]; void build() { for(int i=2;i<=1000000;i++) if(!np[i]) { p[cnt++]=i; if(i<=1000) for(int j=i*i;j<=1000000;j+=i)np[j]=1; } } ll fp(ll a,ll k) { ll res=1LL; while(k>0) { if(k&1)res=res*a%Mod; a=a*a%Mod; k>>=1; } return res; } int pp[25]; int get_pow(int n,int p) { int loc=0; while(n>0) { pp[loc++]=n%p; n/=p; } int cnt=0,flag=0; for(int i=0;i<loc-1;i++) { if(pp[i]<p-1+flag) { cnt++; flag=1; } } return cnt; } int main() { build(); int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); ll ans=1LL; for(int i=0;i<cnt && p[i]<=n;i++) { ans=ans*fp(p[i],get_pow(n,p[i]))%Mod; } printf("%I64d\n",ans); } return 0; }