LightOJ 1067 Combinations

求 \(C_n^k\%p\),\(C\) 为组合数,\(p=1000003\),是个质数



前置芝士:

费马小定理

\(a^{p-1} \equiv a \mod p\) , \(p\) 为质数(费马小定理)

二项式定理
\[
(a+b)^n=\sum_{i=0}^n{C_n^i}*a^i*b^{n-i}
\]
当然,因为组合数是对称的,所以也可以写成
\[
(a+b)^n=\sum_{i=0}^n{C_n^i}*a^{n-i}*b^i
\]
柿子1

\((a+b)^p \equiv a^p+b^p \mod p\),\(p\) 为质数

证明:

由把 \(a+b\) 看成一个整体,由费马小定理得 \((a+b)^p \equiv (a+b) \mod p\)

由费马小定理得 \(a \equiv a^p \mod p\) , \(b \equiv b^p \mod p\)

所以 \((a+b)^p \equiv (a+b) \equiv (a^p+b^p) \mod p\)

柿子2

\((1+x)^p \equiv (1+x^p) \mod p\)

直接代入柿子1即可

卢卡斯定理
\[
C_n^m\%p=C_{\lfloor \frac np \rfloor}^{\lfloor \frac mp \rfloor}*C_{\lfloor n\%p \rfloor}^{\lfloor m\%p \rfloor}\%p
\]
证明:

设 \(b=n\%p\),


\[
(1+x)^n=(1+x)^{\lfloor \frac np \rfloor*p}*(1+x)^b
\]
由柿子2得
\[
\equiv (1+x^p)^{\lfloor \frac np \rfloor}*(1+x)^b \mod p
\]
由二项式定理得
\[
\equiv (\sum_{i=0}^{{\lfloor \frac np \rfloor}}{C_{\lfloor \frac np \rfloor}^i}*x^{pi})*(\sum_{j=0}^bC_b^j*x^j) \mod p
\]
我们把这个柿子叫做 \(tanao\) 柿 ,把它暴力展开一下
\[
tanao=(C_{\lfloor \frac np \rfloor}^0*x^{0p}+C_{\lfloor \frac np \rfloor}^1*x^{1p}+...+C_{\lfloor \frac np \rfloor}^{\lfloor \frac np \rfloor}*x^{{\lfloor \frac np \rfloor}*p})*(C_b^0*x^0+C_b^1*x^1+...+C_b^b*x^b)
\]
我们把 \(tanao\) 柿 里面所有的 \(x^m\) 项都拿出来加在一起记为 \(Q\) ,那么这个 \(Q=A*x^m\)

其中,\(A=\sum C_{\lfloor \frac np \rfloor}^i*C_b^j\) , \((pi+j=m)\),因为 \(b=n\%p,j\le b\) 所以 \(j<p\)

我们再把原来那个 \((1+x)^n\) 用二项式定理展开
\[
(1+x)^n=\sum_{i=0}^n{C_n^i}*x^i
\]
我们发现 \(x^i\) 项对应的系数恰好是 \(C_n^i\)

也就是说,我们上面 \(x^m\) 项对应的系数恰好是 \(C_n^m\)

即,\(C_n^m \equiv A \equiv \sum C_{\lfloor \frac np \rfloor}^i*C_b^j \mod p\) , \((pi+j=m,j<p)\)

所以我们现在有,\(pi+j=m,j<p,b=n\%p\)

可以得出
\[
\left\{
\begin{aligned}
i=\lfloor \frac mp \rfloor,\j=m\%p, \b=n\%p,
\end{aligned}
\right.
\]
然后你定睛一看,\(i,j,b\) 都是唯一的。。。。

那就把可以把 \(\Sigma\) 扔掉了,然后回代
\[
C_n^m \equiv C_{\lfloor \frac np \rfloor}^{\lfloor \frac mp \rfloor}*C_{\lfloor n\%p \rfloor}^{\lfloor m\%p \rfloor} \mod p
\]

\[
C_n^m \%p = C_{\lfloor \frac np \rfloor}^{\lfloor \frac mp \rfloor}*C_{\lfloor n\%p \rfloor}^{\lfloor m\%p \rfloor} \%p
\]
\(wonderful!\)

好,我们现在可以开始做题了

先把 \(C_n^m\) 里的 \(n,m\) 用卢卡斯递归降到 \(p\) 以下,然后再计算,递归回来

\(n,m\) 小于 \(p\) 的时候就好做了,先预处理出 \(p\) 以内的阶乘 \(f[i]=1*2*...*n\%p\) \(O(n)\) 预处理出来,然后用阶乘公式 \(C_n^m=\frac {n!}{m!(n-m)!}\) 计算,注意这里是膜 \(p\) 意义下,所以算除法要用乘法逆元,直接费马小定理即可

时间复杂度 \(O(\)很快\()\)

// This code Write By chtholly_micromaker(MicroMaker)
#include <cstdio>
#include <cctype>
#define reg register
#define int long long
using namespace std;
const int p=1e6+3;
template <class t> inline void rd(t &s)
{
    s=0;
    reg char c=getchar();
    while(!isdigit(c))
        c=getchar();
    while(isdigit(c))
        s=(s<<3)+(s<<1)+(c^48),c=getchar();
    return;
}
int f[p+100];
inline void Init()
{
    f[0]=1;
    for(int i=1;i<=p;++i)
        f[i]=f[i-1]*i%p;
    return;
}
inline int fastpow(int a,int b)
{
    reg int res=1;
    a%=p;
    for(;b;b>>=1,a=a*a%p)
        if(b&1)
            res=res*a%p;
    return res;
}
inline int inv(int x)
{
    return fastpow(x,p-2);
}
inline int C(int n,int m)
{
    if(m>n)
        return 0;
    return f[n]*(fastpow(f[m]*f[n-m]%p,p-2))%p;
}
inline int Lucas(int n,int m)
{
    if(!m)
        return 1;
    return C(n%p,m%p)*Lucas(n/p,m/p)%p;
}
inline void work()
{
    int n,m;
    rd(n);rd(m);
    printf("%lld\n",Lucas(n,m));
}
signed main(void)
{
    Init();
    int t;rd(t);
    for(int i=1;i<=t;++i)
        printf("Case %lld: ",i),work();
    return 0;
}

原文地址:https://www.cnblogs.com/chinesepikaync/p/12301492.html

时间: 2024-10-06 09:02:33

LightOJ 1067 Combinations的相关文章

LightOJ - 1067 - Combinations(组合数)

链接: https://vjudge.net/problem/LightOJ-1067 题意: Given n different objects, you want to take k of them. How many ways to can do it? For example, say there are 4 items; you want to take 2 of them. So, you can do it 6 ways. Take 1, 2 Take 1, 3 Take 1, 4

Light OJ 1067 Combinations (乘法逆元)

Description Given n different objects, you want to take k of them. How many ways to can do it? For example, say there are 4 items; you want to take 2 of them. So, you can do it 6 ways. Take 1, 2 Take 1, 3 Take 1, 4 Take 2, 3 Take 2, 4 Take 3, 4 Input

LightOJ 1067 组合数取模

Description Given n different objects, you want to take k of them. How many ways to can do it? For example, say there are 4 items; you want to take 2 of them. So, you can do it 6 ways. Take 1, 2 Take 1, 3 Take 1, 4 Take 2, 3 Take 2, 4 Take 3, 4 Input

1067 - Combinations---LightOj(Lucas求组合数)

题目链接:http://lightoj.com/volume_showproblem.php?problem=1067 模板求C(n,m)%p, Lucas模板; #include <iostream> #include <stdio.h> #include <string.h> #include <string> #include <vector> #include <algorithm> #include <map>

17. Letter Combinations of a Phone Number

Given a digit string, return all possible letter combinations that the number could represent. A mapping of digit to letters (just like on the telephone buttons) is given below. Input:Digit string "23" Output: ["ad", "ae", &q

LightOJ 1030 Discovering Gold【概率】

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1030 题意:基础概率题. 代码: #include <stdio.h> #include <string.h> #include <vector> #include <string> #include <algorithm> #include <iostream> #include <iterator>

ytu 1067: 顺序排号(约瑟夫环)

1067: 顺序排号Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 31  Solved: 16[Submit][Status][Web Board] Description 有n人围成一圈,顺序排号.从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来的第几号的那位. Input 初始人数n Output 最后一人的初始编号 Sample Input 3 Sample Output 2 HINT Source freepro

LightOJ - 1370 Bi-shoe and Phi-shoe

题目链接:http://lightoj.com/login_main.php?url=volume_showproblem.php?problem=1370 题目大意:给N个数a[i], N <= 1e6,问使 Φ(x) >= a[i] 成立的最小x的所有x的和是多少. 解题思路:我们知道的是对于素数 m 来说,phi[m] = m - 1.另一方面,对于一个合数 m 来说, phi[m] < phi[x] , x > m && x 是素数. 因此,我们可以认为,每

lightoj 1057 - Collecting Gold(状压dp)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1057 题解:看似有点下记忆话搜索但是由于他是能走8个方向的也就是说两点的距离其实就是最大的x轴或y轴的差.然后只有15个藏金点状压一下加dfs就行了. #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #define inf 0X3f3f3f