lucas数论定理学习

2015ICPC长春网络赛1010 考到了lucas+crt(中国剩余定理)

赛后补题ing。。

卢卡斯定理的百度百科

证明来自一本《初等数论》非常赞!


hdu3037

模板题

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <set>
#include <string>
#include <map>
#include <queue>
//#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 100001;
const int mod = 10007;
const int inf = 0x7f7f7f7f;
const double eps = 1e-4;

#define pb push_back
#define fi first
#define se second
#define mp make_pair
#define pii pair<int,int>

int N, M, P;
int aa[maxn];

int inv(int n,int p) {
    int m=1, k=p-2;
    while(k) {
        if(k&1) m=1ll*m*n%p;
        k>>=1; n=1ll*n*n%p;
    }
    return m;
}
int Cm(int n,int m,int p) {
    if(m>n) return 0;
    return aa[n]*1ll*inv(aa[m],p)*inv(aa[n-m],p)%p;
}
ll lucas(int n,int m,int p) {
    if(!m) return 1;
    return lucas(n/p,m/p,p)*Cm(n%p,m%p,p)%p;
}

int main() {
    int T; cin>>T; aa[0]=1;
    while(T--) {
        scanf("%d%d%d", &N, &M, &P);
        for(int i=1;i<P;i++) aa[i]=aa[i-1]*1ll*i%P;
        printf("%d\n", (int)lucas(N+M,M,P) );
    }
    return 0;
}


hdu4349

 C(n,0),C(n,1),C(n,2)...C(n,n).里面有几个奇数

对于C(n,m)是否为奇数就是求C(n,m)%2,lucas~

n,m写成2进制:n=a[k]a[k-1]...a[0],m=b[k]b[k-1]...b[0]

如果存在一个a[i]<b[i],则 C (n,m)%2=0

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <set>
#include <string>
#include <map>
#include <queue>
//#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 100001;
const int mod = 10007;
const int inf = 0x7f7f7f7f;
const double eps = 1e-4;

#define pb push_back
#define fi first
#define se second
#define mp make_pair
#define pii pair<int,int>

int N, M, P;
int aa[maxn];

int inv(int n,int p) {
    int m=1, k=p-2;
    while(k) {
        if(k&1) m=1ll*m*n%p;
        k>>=1; n=1ll*n*n%p;
    }
    return m;
}
int Cm(int n,int m,int p) {
    if(m>n) return 0;
    return aa[n]*1ll*inv(aa[m],p)*inv(aa[n-m],p)%p;
}
ll lucas(int n,int m,int p) {
    if(!m) return 1;
    return lucas(n/p,m/p,p)*Cm(n%p,m%p,p)%p;
}

int main() {
//    int T; cin>>T;
    while(~scanf("%d", &N)) {
        ;
        M=0;
        for(int i=1;i<=N;i<<=1) {
            if(N&i) M++;
        }
        printf("%d\n", 1<<M);
    }
    return 0;
}

hdu 3944


求杨辉三角中从顶点到(n,k)路径和(只能向下或右下,如图)的 路径和的最小值 mod p

例如样例4 2 路径为 (0,0) -> (2,0) -> (4,2)

只考虑终点在左半边的情况,对称可以求右半边

先是路径肯定是直线下降,然后一直右下到达终点,显然这种路只有一条

下降的部分全部为1

右下的部分为 (n-m,0) -> (n,m)

C(n-m,0) + ... + C(n,m)=C(n+1,m)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <set>
#include <string>
#include <map>
#include <queue>
//#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 10001;
const int mod = 10007;
const int inf = 0x7f7f7f7f;
const double eps = 1e-4;

#define pb push_back
#define fi first
#define se second
#define mp make_pair
#define pii pair<int,int>

int N, M, P, K;
//int aa[maxn];
int aap[1230][maxn];

int inv(int n,int p) {
    int m=1, k=p-2;
    while(k) {
        if(k&1) m=m*n%p;
        k>>=1; n=n*n%p;
    }
    return m;
}
int Cm( int n,int m,int p) {
    if(m>n) return 0;
    return aap[K][n]*1ll*inv(aap[K][m],p)*inv(aap[K][n-m],p)%p;
}
int lucas(int n,int m,int p) {
    if(!m) return 1;
    return lucas(n/p,m/p,p)*Cm(n%p,m%p,p)%p;
}
int prim[maxn];
int main() {
//    int T; cin>>T;
    for(int i=2;i<maxn;i++) {
        if(!prim[i]) {
            prim[++prim[0]]=i;
            for(int j=2;i*j<maxn;j++) prim[i*j]=1;
            int p=prim[0];
            aap[p][0]=1;
            for(int j=1;j<i;j++) aap[p][j]=aap[p][j-1]*j%i;
        }
    }
    int kase=1;
    while(~scanf("%d%d%d", &N, &M, &P)) {
        printf("Case #%d: ", kase++ );
        if(2*M>N) M=N-M;
        K=lower_bound(prim+1,prim+prim[0],P)-prim;
        printf("%d\n", (lucas(N+1,M,P)+N-M)%P );
    }
    return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值