hdu 5407 组合数的lcm

来源:互联网 发布:华测手簿同步软件 编辑:程序博客网 时间:2024/06/06 19:43

hdu 5407 本题求对于给定数n,求n的所有组合数的最小公倍数

若c|a且b|a, 则lcm(a/c, a/b) = a/gcd(c, b);

因此

lcm(n!/0!n!,  n!/1!(n-1)!,  n!/2!(n-1)!,  n!/i!(n-i)!.....) =

 n ! / gcd(0!n!,   1!(n-1)!,   2!(n-1)!,   i!(n-i)!.....)

n!中个质因子p的次数为∑_(j=1)^∞[n/p^j ]

 i!(n-i)!中质因子p的次数为∑_(j=1)^∞[i/p^j +(n-i)/p^j ]

当且仅当(n+1)%(p^j)==0  对于任意的i, n/p^j == i/p^j+ (n-i)/p^j

所以只要(n+1)%(p^j) !=0 必有一个i使得n/p^j > i/p^j+ (n-i)/p^j 且 n/p^j - i/p^j - (n-i)/p^j  = 1;即分子会比分母多一个p

因此只要有一个(n+1)%(p^j) !=0 ,答案就多乘一个p

齿刚唇柔,刚者不如柔者久,柔能克刚; 眉先须后,先生还是后生长 ,后来居上


#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <algorithm>#include <set>#include <cmath>#include <queue>#define MAXN 1000010#define ll long longusing namespace std;const ll mod = 1000000007;int prim[MAXN];bool vis[MAXN];int tot;void work(){    memset(vis, 0, sizeof(vis));    tot = 0;    prim[tot++] = 2;    int t = 1000000;    for(int i = 3; i <= t; i+= 2)    {        if(vis[i]) continue;        for(ll j = (ll)i*i; j <= t; j += 2*i)            vis[j] = true;        prim[tot++] = i;    }}int main(){    work();    //freopen("in.txt", "r", stdin);    int t;    cin >> t;    while (t--)    {        ll ans = 1;        int n;        scanf("%d", &n);        int tag = 0;        for (int i=0; i<tot; i++)        {            ll tmp = prim[i];            while (tmp <= n)            {                if ((n+1)%tmp!=0)                    ans = ans*prim[i]%mod;                tmp *= prim[i];            }        }        printf("%I64d\n", ans);    }    return 0;}


0 0