数论基础题 费马引理+卡特兰数+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定理+同余方程+扩欧的主要内容,如果未能解决你的问题,请参考以下文章

HDU 3037 Saving Beans (数论,Lucas定理)

退役前的数学学习

数论及其应用——同余式定理

hdu 3037 费马小定理+逆元求组合数+Lucas定理

数论Lucas定理

『基础同余和费马小定理』