您的位置:首页 > 其它

lucas数论定理学习

2015-09-14 23:54 267 查看
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
*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
*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]
*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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: