组合数(阶乘数质因子分解)

C(n,m)   表示组合数,n>=m>=0

以下适用范围:

n<=1e6(or 1e7...)

爆龙龙的答案需取模,允许取合数模

时间复杂度 线性筛略大一点点 大概还是nlon(n)

C(n,m)=n!/(m!*(n-m)!)

举例说明一下为什么可以通过下面代码去计算阶乘数的所有质因子各自的数目。

void factor_jc(int n)//分解n!的素数因子并记录个数
{
    //fac[i]=(prim[i]这个素数因子有几个)
    int i,up=n;for(i=1;i<=pri[0]&&pri[i]<=up;i++)
    {
        int tmp=n;
        while(tmp)
        {
            fac[i]+=tmp/pri[i];
            tmp/=pri[i];
        }
    }
    //fac[0]存素数最大到prim[]几;
    fac[0]=max(fac[0],i);
}

比如求9!中质因子的个数:

2的个数=9/2+9/22+9/23=4+2+1=7

因为

  包含因子  2:2  4  6  8:fac[2]+=4(此时4和8仅记录第一个因子2)

  包含因子22:    4      8:fac[2]+=2 (此时4和8记录了第二个因子2)

  包含因子23:            8:fac[2]+=1 (此时8记录第三个因子2)

所以因子2的个数等于4+2+1=7;

同理:

因为

  包含因子  3:3  6  9:fac[3]+=3(此时9仅记录第一个因子3)

  包含因子22:        9:fac[3]+=1 (此时9记录了第二个因子3)

所以因子3的个数等于9/3+9/32=3+1=4;

所以对于n!包含质因子x个数:fac[x]=n/x+n/x2+……+n/xk  (直到n/xk=0结束)。

所以对于9!:

fac[2]=9/2+9/22+9/23=4+2+1=7;

fac[3]=9/3+9/32=3+1=4;

fac[5]=9/5=1;

fac[7]=9/7=1;

因为下一个素数是11>9,所以结束。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+50;
const ll mod=1e9+7;
int pri[maxn+5],fac[maxn+5];
void prime()
{
    //prime[0]记录素数个数
    memset(pri,0,sizeof(pri));
    for(int i=2;i<=maxn;i++)
    {
        if(!pri[i]) pri[++pri[0]]=i;
        for(int j=1;j<=pri[0]&&pri[j]<=maxn/i;j++)
        {
            pri[pri[j]*i]=1;
            if(i%pri[j]==0) break;
        }
    }
}
void factor_jc(int n)//分解n!的素数因子并记录个数
{
    //fac[i]=(prim[i]这个素数因子有几个)
    int i,up=n;
    if(up<0)up=-up;
    for(i=1;i<=pri[0]&&pri[i]<=up;i++)
    {
        int tmp=n;
        while(tmp)
        {
            fac[i]+=tmp/pri[i];
            tmp/=pri[i];
        }
    }
    //fac[0]存素数最大到prim[]几;
    fac[0]=max(fac[0],i);
}
ll kpow(ll a,ll b)
{
    ll ans=1,base=a;
    while(b)
    {
        if(b&1) ans=ans*base%mod;
        base=base*base%mod;
        b>>=1;
    }
    return ans;
}
ll C(int n,int m)
{
    memset(fac,0,sizeof(fac));
    factor_jc(n);
    factor_jc(-m);//负数代表减 减去因子
    factor_jc(m-n);//
    ll ans=1;
    for(int i=1;i<fac[0];i++)
        if(fac[i])ans=ans*kpow(pri[i],fac[i])%mod;
    return ans;
}
int main()
{
    int n,m;
    prime();
    while(~scanf("%d%d",&n,&m))
        printf("%lld\n",C(n,m));
}

原文地址:https://www.cnblogs.com/kkkek/p/11450696.html

时间: 2024-10-30 10:26:04

组合数(阶乘数质因子分解)的相关文章

BZOJ 1485: [HNOI2009]有趣的数列 [Catlan数 质因子分解]

1485: [HNOI2009]有趣的数列 Description 我们称一个长度为2n的数列是有趣的,当且仅当该数列满足以下三个条件: (1)它是从1到2n共2n个整数的一个排列{ai}: (2)所有的奇数项满足a1<a3<…<a2n-1,所有的偶数项满足a2<a4<…<a2n: (3)任意相邻的两项a2i-1与a2i(1≤i≤n)满足奇数项小于偶数项,即:a2i-1<a2i. 现在的任务是:对于给定的n,请求出有多少个不同的长度为2n的有趣的数列.因为最后的答

hdu5392--Infoplane in Tina Town(置换群+质因子分解求最小公倍数)

题目链接:点击打开链接 题目大意:给出一种操作a[1],a[2],,,,a[n],代表每交换一次,1位置的数到a[1]位置,2位置的数到a[2]位置,,, 问最终交换多少次可以恢复初始的情况. 题目给出一个置换,要求置换的次数,也就是所有轮换个数的最小公倍数.首先求出所有轮换的个数,然后求最小公倍数的时候不能用gcd,因为Mod的取余太大,所以用质因子分解,统计每个质因子出现的最多次数,计算最终的值. #include <cstdio> #include <cstring> #in

数学问题——质因子分解

所谓质因子分解是指将一个正整数 n 写成一个或多个质数的乘积形式,例如 24=2*2*2*3.显然,由于最后都要归结到若干不同质数的乘积,不妨先把素数表打印出来. 由于每个质因子都可以不止出现一次,因此不妨定义结构体 factor ,用来存放质因子及其个数,如下所示: 1 struct factor { 2 int x, cnt; // x 为质因子,cnt 为其个数 3 } fac[10]; 而有一个结论:对一个正整数 n 来说,如果它存在 [2,n] 范围内的质因子,要么这些质因子全部小于等

hdoj 1492 The number of divisors(约数) about Humble Numbers 【数论】【质因子分解 求和】

定理:一个正整数 n 可以用素因子唯一表示为 p1^r1 * p2^r2 * ... pk^rk (其中 pi 为素数) , 那么这个数的因子的个数就是,(r1+1)*(r2+1)*...*(rk+1). 理解:为什么是加1之后再相乘,因为一个数的的因子数至少为1和他自身,但因为r1,r2..可以为0,所以因子的个数为(r1+1)... 拓展一下: 定理1: 一个正整数 n 可以用素因子唯一表示为 p1^r1 * p2^r2 * ... pk^rk (其中 pi 为素数) , 那么这个数的因子的

HDU 2601 An easy problem(暴力枚举/质因子分解)

An easy problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 7963    Accepted Submission(s): 1920 Problem Description When Teddy was a child , he was always thinking about some simple math p

luogu P2043 质因子分解

题目描述 对N!进行质因子分解. 输入输出格式 输入格式: 输入数据仅有一行包含一个正整数N,N<=10000. 输出格式: 输出数据包含若干行,每行两个正整数p,a,中间用一个空格隔开.表示N!包含a个质因子p,要求按p的值从小到大输出. 输入输出样例 输入样例#1: 10 输出样例#1: 2 8 3 4 5 2 7 1 说明 10!=3628800=(2^8)*(3^4)*(5^2)*7 质因数分解.. #include<cstdio> const int maxn=100006;

POJ1845:Sumdiv(求因子和+逆元+质因子分解)好题

题目链接:http://poj.org/problem?id=1845 定义: 满足a*k≡1 (mod p)的k值就是a关于p的乘法逆元. 为什么要有乘法逆元呢? 当我们要求(a/b) mod p的值,且a很大,无法直接求得a/b的值时,我们就要用到乘法逆元. 我们可以通过求b关于p的乘法逆元k,将a乘上k再模p, 即(a*k) mod p.其结果与(a/b) mod p等价. 题目解析:让求a^b的因子和modk,因为是大数没法直接求,因为求因子和函数是乘性函数,所以首先要质因子分解,化成n

uva10780 质因子分解

UVA - 10780 Again Prime? No Time.(uva卡得一逼,所以还是把vj的链接贴一下把) 题意:给出n,m,使得m^k是n!的因子,求最大的k 思路:质因子分解,将m 和n!都分解为 p1^a1*p2^a2*...pn^an,其中p1 p2...pn是连续的质数2,3,5,7...,用一个数组记录每个质数的次幂ai,然后二分答案k,只有当m分解的质因子的次幂*k全部小于等于n!分解的质因子次幂,m^k才是n!的因子,比较坑的一点是,当k=0时是作为无解的情况的 AC代码

UVA - 10780 Again Prime? No Time. (质因子分解)

Description Again Prime? No time. Input: standard input Output: standard output Time Limit: 1 second The problem statement is very easy. Given a number n you have to determine the largest power of m, not necessarily prime, that divides n!. Input The