数论基础题 费马引理+卡特兰数+Lucas定理+同余方程+扩欧
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数论基础题 费马引理+卡特兰数+Lucas定理+同余方程+扩欧相关的知识,希望对你有一定的参考价值。
1119 机器人走方格 V2
费马引理+组合数
预处理的解法一错了,但复杂度是对的,不知道为啥卡了
#include<iostream>
#define int long long
#define endl '\\n'
using namespace std;
const int inf=1e18;
const int N=1e6+5;
const int mod=1e9+7;
int m,n,fac[N],inv[N];
int qpow(int x,int y)
int res=1;
while(y)
if(y&1) res=res*x%mod;
x=x*x%mod;y>>=1;
return res;
int getinv(int x)return qpow(x,mod-2);
int C(int n,int m)
return fac[n]*inv[m]%mod*inv[n-m]%mod;
int C1(int n,int m)
m=min(m,n-m);
int res=1,g=1;
for(int i=1;i<=m;i++)
res=res*(n-i+1)%mod;
g=g*i%mod;
return res*getinv(g)%mod;
void solve()
// fac[0]=1;
// for(int i=1;i<=1000000;i++) fac[i]=fac[i-1]*i%mod;
// inv[1000000]=getinv(fac[1000000]);
// for(int i=1000000;i>=1;i--)
// inv[i-1]=inv[i]*i%mod;
cin>>m>>n;
cout<<C1(n+m-2,m-1)<<endl;
signed main()
//cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
//int T;cin>>T;
//while(T--)
solve();
return 0;
卡特兰数
前几项分别为: 1, 2, 5, 14, 42, 132, 429……
公式:f(x)=C(2*n,n) * (1/n+1)
------>经过化简:f(x)=(2n!)/((n+1)!*(n!))
Lucas定理
求较大组合数的情况下使用,用来求C(n,m) mod p的值
1120 机器人走方格 V3
扩欧求逆元
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
using namespace std;
const int inf=1e18;
const int N=1e6+5;
const int mod=1e4+7;
int m,n,fac[N],inv[N];
int qpow(int x,int y)
int res=1;
while(y)
if(y&1) res=res*x%mod;
x=x*x%mod;y>>=1;
return res;
int getinv(int x)return qpow(x,mod-2);
int ex_gcd(int a,int b,int &x,int &y)
if(b==0)
x=1,y=0;return a;
int gcd=ex_gcd(b,a%b,y,x);
y-=a/b*x;
return gcd;
int Cal(int a,int b,int c)
int x,y;
int gcd=ex_gcd(a,b,x,y);
if(c%gcd) return -1;
x*=c/gcd;
b/=gcd;
if(b<0) b=-b;
int ans=x%b;
if(ans<=0) ans+=b;
return ans;
int C(int n,int m)
if(m>n) return 0;
int ans=1;
for(int i=1;i<=m;i++)
int a=(n-i+1)%mod,b=i%mod;
int g=Cal(b,mod,1);
//ans=ans*(a*qpow(b,mod-2)%mod)%mod;
ans=ans*(a*g%mod)%mod;
return ans;
int lucas(int a,int b)
if(b==0) return 1;
return C(a%mod,b%mod)*lucas(a/mod,b/mod)%mod;
void solve()
cin>>n;
n--;
cout<<lucas(2 * n, n)*getinv(n+1)* 2 % mod<<endl;
signed main()
//cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
//int T;cin>>T;
//while(T--)
solve();
return 0;
同余方程
a-b=m ----->a%m==b%m
Reduced ID Numbers
#include <iostream>
#include<map>
#include<cstdio>
#include<cstring>
#include<stdlib.h>
//#define int long long
#define endl '\\n'
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
const int inf=1e18;
const int N=1e6+5;
int n,a[N];
bool vis[N],ok[N];
signed main()
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int T;
cin>>T;
while(T--)
cin>>n;
mem(vis,0);
for (int i = 1; i <= n; ++i) cin>>a[i];
for(int i=1; i<=n; i++)
for(int j=i+1; j<=n; j++)
vis[abs(a[i]-a[j])]=1;
bool flag=0,f2=0;
for(int i=n;!f2; i++)
if(vis[i]) continue;
mem(ok,0);
flag=0;
for(int j=1; j<=n&&!flag; j++)
if(ok[a[j]%i])
flag=1;
else
ok[a[j]%i]=1;
if(flag==0)
cout<<i<<endl;
f2=1;
return 0;
青蛙的约会
扩展欧几里得
#include<iostream>
#define int long long
#define endl '\\n'
using namespace std;
const int inf=1e18;
const int N=1e6+5;
int x,y,m,n,l;
int ex_gcd(int a,int b,int &x,int &y)
if(b==0)
x=1,y=0;return a;
int gcd=ex_gcd(b,a%b,y,x);
// int gcd=ex_gcd(b,a%b,x,y);
// int tmp=x;
// x=y;
// y=tmp-(a/b)*y;
y-=a/b*x;
return gcd;
int Cal(int a,int b,int c) //求解最小的x使得ax+by=c
int x,y;
int gcd=ex_gcd(a,b,x,y);
if(c%gcd) return -1;
x*=c/gcd;
b/=gcd;
if(b<0) b=-b;
int ans=x%b;
if(ans<=0) ans+=b;
return ans;
void solve()
cin>>x>>y>>m>>n>>l;
int a=n-m,b=l,c=x-y;
int ans=Cal(a,b,c);
if(ans!=-1)
cout<<ans<<endl;
else
cout<<"Impossible"<<endl;
signed main()
//cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
//int T;cin>>T;
//while(T--)
solve();
return 0;
The Balance
砝码A放左边,药物在右边,扩欧求出正值说明在左,否则在右;
砝码B在左边……(同理)
#include<iostream>
#include<cmath>
#include<stdlib.h>
#define int long long
#define endl '\\n'
using namespace std;
const int inf=1e18;
const int N=1e6+5;
const int mod=1e4+7;
int a,b,d;
int qpow(int x,int y)
int res=1;
while(y)
if(y&1) res=res*x%mod;
x=x*x%mod;
y>>=1;
return res;
int getinv(int x)
return qpow(x,mod-2);
int ex_gcd(int a,int b,int &x,int &y)
if(b==0)
x=1,y=0;
return a;
int gcd=ex_gcd(b,a%b,x,y);
int tmp=x;
x=y;
y=tmp-a/b*y;
return gcd;
int Cal(int a,int b,int c)
int x,y;
int gcd=ex_gcd(a,b,x,y);
if(c%gcd) return -1;
// (x,y)是ax+by=c的一组解
x=x*c/gcd;
//y=y*c/gcd;
b/=gcd;
if(b<0) b=-b;
int ans=(x%b+b)%b;
return ans;
void solve()
while(cin>>a>>b>>d&&a&&b&&d)
int x1=Cal(a,b,d);
int y1=(x1*a-d)/b;
if(y1<0) y1=-y1;
int y2=Cal(b,a,d);
int x2=(y2*b-d)/a;
if(x2<0) x2=-x2;
if(x1+y1<x2+y2||(x1+y1==x2+y2&&x1*a+y1*b<x2*a+y2*b))
cout<<x1<<" "<<y1<<endl;
else
cout<<x2<<" "<<y2<<endl;
signed main()
//cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
//int T;cin>>T;
//while(T--)
solve();
return 0;
以上是关于数论基础题 费马引理+卡特兰数+Lucas定理+同余方程+扩欧的主要内容,如果未能解决你的问题,请参考以下文章