[模板][数论][gcd+exgcd+sieve+power+euler_phi+euler_table+inv]

NOIP临近,,写写模板。。。


求逆元:
扩展欧几里得求逆元
适用范围:常数小,适合单个求逆元
限制:gcd(a,n)==1

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define FROP "inv"
#define LL long long
using namespace std;
int n=100,mod=1e9+7,inv[105];
void exgcd(int a,int b,int& d,int &x,int &y)
{
    if(!b){d=a;x=1;y=0;}
    else {exgcd(b,a%b,d,y,x);y-=x*(a/b);}
}
int main()
{
    freopen(FROP".out","w",stdout);
    for(int i = 1; i <= n; i++)
    {
        int d,x,y;
        exgcd(i,mod,d,x,y);//i mod mod 的逆元
        inv[i]=(x%mod+mod)%mod;
    }
    for(int i = 1; i <= n; i++)
        printf("%d,",inv[i]);
    return 0;
}

费马小定理求逆元
适用范围:若mod是,inv=a^(mod-2)
否则inv=a^(phi(mod)-1),,所有前提条件,a,与mod互素。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define FROP "inv"
#define LL long long
using namespace std;
int n=100,mod=1e9+7,inv[105];
int euler_phi(int n)
{
    int ans=n;
    int m= sqrt(n+0.5);
    for(int i = 2; i <= m; i++)if(n % i==0)
    {
        ans=ans/i*(i-1);
        while(n%i==0)n/=i;
    }
    if(n>1)ans=ans/n*(n-1);
    return ans;
}
int power(int a,int b)
{
    if(!b)return 1;
    if(b==1)return a;
    int p=power(a,b/2);
    p=(LL)p*p%mod;
    if(b%2)return p*a%mod;
    return p;
}
int main()
{
    freopen(FROP".out","w",stdout);
        int eul=euler_phi(mod);
    for(int i= 1; i <= 100; i++)
    {
        printf("%d,",power(i,eul-1));
    }
    return 0;
}

线性求逆元
没有限制,,表示爱上线性求逆元了。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define FROP "inv"
#define LL long long
using namespace std;
int n=100,mod=1e9+7,inv[105];
int main()
{
    freopen(FROP".out","w",stdout);
    inv[1]=1;
    for(int i = 2; i <= n; i++)
        inv[i]=(LL)(mod-mod/i)*inv[mod%i]%mod;
    for(int i = 1;i <= n; i++)
        printf("%d,",inv[i]);
    return 0;
}

gcd模板

int gcd(int a,int b){return b==0?a:gcd(b,a%b);}

筛法求素数

void sieve(int n)
{
    int m = sqrt(n+0.5);
    for(int i = 2; i <= m; i++)if(!vis[i])
        for(int j = i*i; j <= n; j+=i)vis[j]=1;
}
int main()
{
    freopen(FROP".in","r",stdin);
    freopen(FROP".out","w",stdout);
    sieve(100);
    for(int i = 1;i <= n; i++)
        if(!vis[i])printf("%d,",i);
    return 0;
}

单数欧拉函数

int euler_phi(int n)
{
    int ans=n;
    int m= sqrt(n+0.5);
    for(int i = 2; i <= m; i++)if(n % i==0)
    {
        ans=ans/i*(i-1);
        while(n%i==0)n/=i;
    }
    if(n>1)ans=ans/n*(n-1);
    return ans;
}

求1-n的欧拉函数
O(nloglogn)

int phi[100];
void euler_table(int n)
{
    for(int i = 2; i <= n; i++)phi[i]=0;
    phi[1]=1;
    for(int i = 2; i <= n;i++)if(!phi[i])
        for(int j= i; j <= n; j+=i)
        {
            if(!phi[j])phi[j]=j;
            phi[j]=phi[j]/i*(i-1);
        }
}

快速幂

int power(int a,int b)
{
    if(!b)return 1;
    if(b==1)return a;
    int p=power(a,b/2);
    p=(LL)p*p%mod;
    if(b%2)return p*a%mod;
    return p;
}

差不多了,还有些以后再说吧。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值