LightOJ 1067 Combinations

Posted chinesepikaync

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 floor}^{lfloor frac mp floor}*C_{lfloor n\%p floor}^{lfloor m\%p floor}\%p ]
证明:

(b=n\%p)


[ (1+x)^n=(1+x)^{lfloor frac np floor*p}*(1+x)^b ]
由柿子2得
[ equiv (1+x^p)^{lfloor frac np floor}*(1+x)^b mod p ]
由二项式定理得
[ equiv (sum_{i=0}^{{lfloor frac np floor}}{C_{lfloor frac np floor}^i}*x^{pi})*(sum_{j=0}^bC_b^j*x^j) mod p ]
我们把这个柿子叫做 (tanao) 柿 ,把它暴力展开一下
[ tanao=(C_{lfloor frac np floor}^0*x^{0p}+C_{lfloor frac np floor}^1*x^{1p}+...+C_{lfloor frac np floor}^{lfloor frac np floor}*x^{{lfloor frac np floor}*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 floor}^i*C_b^j) , ((pi+j=m)),因为 (b=n\%p,jle 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 floor}^i*C_b^j mod p) , ((pi+j=m,j<p))

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

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

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

[ C_n^m \%p = C_{lfloor frac np floor}^{lfloor frac mp floor}*C_{lfloor n\%p floor}^{lfloor m\%p floor} \%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
",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;
}

以上是关于LightOJ 1067 Combinations的主要内容,如果未能解决你的问题,请参考以下文章

[Lintcode]152. Combinations/[Leetcode]77. Combinations

Combinations

itertools mode 之 combinations用法

77. Combinations

python 全排列combinations和permutations函数

启动mysql服务失败,错误码:1067.