线性求逆元等 数论板子

#pragma GCC optimize(2)

逆元板子块

 

先来一个线性求逆元

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100005;
const int mod=(int)1e9+7;
ll inv[maxn],a[maxn],n;
int main(){
    inv[1]=1;
    for(int i=2;i<maxn;i++){
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    }


    return 0;
}

也可以递归求  复杂度为logn

ll inv(ll n){
    if(n==1)
        return 1;
    return (mod-mod/n)*(inv(mod%n))%mod;
}

再加上一个阶乘的线性求逆元板子

    fac[0]=fac[1]=1;
    for(ll i=2;i<maxn;i++)
        fac[i]=fac[i-1]*i%mod;
    
    inv_fac[maxn-1]=quick(fac[maxn-1],mod-2);
    for(int i=maxn-2;i>=0;i--)
        inv_fac[i]=inv_fac[i+1]*(i+1)%mod;

 

辗转相除法求逆元1

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x=1;
        y=0;
        return a;
    }
    ll r=exgcd(b,a%b,x,y);
    ll t=x%mod;
    x=y%mod;
    y=((t-a/b*y)%mod+mod)%mod;
    return r;
}
//求2对于1e9+7的逆元就是 exgcd(2,1e9+7,x,y),其中x的值就是inv2,
int main(){
    ll a;
    while(~scanf("%lld",&a)){
       ll x=1,y=1;
       exgcd(a,mod,x,y);
       printf("%lld\n",x);
    }
	return 0;
}

辗转相除法求逆元2

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll extend_gcd(ll a,ll b,ll &x,ll &y) {
    if(a==0&&b==0) return -1;//无最大公约数
    if(b==0){x=1;y=0;return a;}
    ll d=extend_gcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}
//*********求逆元素*******************
//ax = 1(mod n)
ll mod_reverse(ll a,ll n)  {
    ll x,y;
    ll d=extend_gcd(a,n,x,y);
    if(d==1) return (x%n+n)%n;
    else return -1;
}
int main(){
    ll a;
    while(~scanf("%lld",&a)){
       ll x=1,y=1;
       ll ans=mod_reverse(a,mod);
       printf("%lld\n",ans);
    }
	return 0;
}

 

再来个线性求素数的板子

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000005;
int prime[maxn],numprime,vis[maxn];
void init(){
    for(int i=2;i<maxn;i++){
        if(!vis[i])prime[++numprime]=i;
        for(int j=1;j<=numprime&& prime[j]*i<maxn;j++){
            vis[prime[j]*i]=1;
            if(i%prime[j]==0)break;
        }
    }
}

 

组合数


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int maxn=200005;
ll fac[maxn],inv_fac[maxn],n,m,k;
 
ll quick(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;
        b/=2;
    }
    return ans;
}
void init(){
    inv_fac[0]=fac[0]=1,fac[1]=inv_fac[1]=1;
    for(int i=2;i<maxn;i++)
        fac[i]=fac[i-1]*i%mod;
    inv_fac[maxn-1]=quick(fac[maxn-1],mod-2);
    for(int i=maxn-2;i>=0;i--)
        inv_fac[i]=inv_fac[i+1]*(i+1)%mod;
}
 
ll C(ll n,ll m){
    if(n<0||m<0||m>n) return 0;
    if(n==m||m==0) return 1;
    return fac[n]*inv_fac[n-m]%mod*inv_fac[m]%mod;
}
int main(){
    init();
    int t;
    cin>>t;
    while(t--){

    }
   return 0;
}

 

快速读入的板子


ll read(){
    ll ans=0; char last=' ',ch=getchar();
    while(ch<'0' || ch>'9')last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans; return ans;
}

大神那里搜集来的素数判定  Miller_Rabin算法板子

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int times=20;
int number=0;
map<ll,int>m;
ll Random(ll n){			//生成[ 0 , n ]的随机数
	return ((double)rand()/RAND_MAX*n+0.5);
}
ll quick_mul(ll a,ll b,ll mod){//快速计算 (a*b) % mod
	ll ans=0;
	while(b){
		if(b&1){
			b--;
			ans=(ans+a)%mod;
		}
		b/=2;
		a=(a+a)%mod;
	}
	return ans;
}
ll quick(ll a,ll b,ll mod){
	ll ans=1;
	while(b){
		if(b&1) ans=quick_mul(ans,a,mod);
		b/=2;
		a=quick_mul(a,a,mod);
	}
	return ans;
}
int witness(ll a,ll n){//miller_rabin算法的精华
//用检验算子a来检验n是不是素数
	ll tem=n-1;
	int j=0;
	while(tem%2==0){
		tem/=2;
		j++;
	}//将n-1拆分为a^r * s
	ll x=quick(a,tem,n);//得到a^r mod n
	if(x==1||x==n-1) return 1;	//余数为1则为素数
	while(j--){//否则试验条件2看是否有满足的 j
		x=quick_mul(x,x,n);
		if(x==n-1) return 1;
	}
	return 0;
}
int miller_rabin(ll n){//检验n是否是素数
	if(n==2)
		return 1;
	if(n<2||n%2==0)
		return 0;				//如果是2则是素数,如果<2或者是>2的偶数则不是素数
	for(int i=1;i<=times;i++){  //做times次随机检验
		ll a=Random(n-2)+1; //得到随机检验算子 a
		if(!witness(a,n))//用a检验n是否是素数
			return 0;
	}
	return 1;
}
int main(){
	ll aim;
	while(cin>>aim){
		if(miller_rabin(aim))	//检验tar是不是素数
			cout << "Yes, Prime!" << endl;
		else
			cout << "No, not prime.." << endl;
	}
	return 0;
}

欧拉公式求有多少小于等它并与它互质的数

ll Euler(ll n){ //欧拉函数
    ll ans=n,res=n;
    for(ll i=2;i<=sqrt(n);i++){
        if(!pri[i]){
            if(res%i==0){
                ans=ans/i*(i-1);
                while(res%i==0)
                    res/=i;
            }
        }
    }
    if(res>1)
        ans=ans/res*(res-1);
    return ans;
}

还有一个无质数保存版本

ll Euler(ll x){
    ll ans=x;
    for(ll i=2;i*i<=x;i++){
        if(x%i==0){
            ans=ans-ans/i;
            while(x%i==0)
                x/=i;
        }
    }
    if(x>1)
        ans=ans-ans/x;
    return ans;
}

线性求欧拉+素数

const int maxn=10000005;
int pri[maxn],num;
bool vis[maxn];
ll euler[maxn];
void getpri(){
    for(int i=2;i<maxn;i++){
        if(!vis[i]){
            pri[++num]=i;
            euler[i]=i-1;
        }
        for(int j=1;j<=num&& pri[j]*i<maxn;j++){
            ll now=i*pri[j];
            vis[now]=1;
            if(i%pri[j]==0){ //如果i遇到了自己最小的质因子就直接跳出
                euler[now]=euler[i]*pri[j];
                break;
            }
            else {
                euler[now]=euler[i]*(pri[j]-1);
            }
        }
    }
}

 

求1-n中每个数的欧拉函数

const int maxn=1000005;
void get_euler(){
    euler[maxn];
    for(int i=1;i<maxn;i++)  
        euler[i]=i;  
    for(int i=2;i<maxn;i++)  
        if(euler[i]==i)  
           for(int j=i;j<maxn;j+=i)  
              euler[j]=euler[j]/i*(i-1);  
}

辗转相除法

ll exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x=1,y=0;
        return a;
    }
    else {
        ll d=exgcd(b,a%b,y,x);
        y-=x*(a/b);
        return d;
    }
}

 

高斯消元模板

double A[maxn<<1][maxn],x[maxn];//A矩阵中每一行1~n存系数,n+1为答案,m个方程m行,x是最终的答案
//注意空间要多开几个,还要考虑n,m不同的情况
int n,m;
int Guass(int n,int m){//n个未知数,m个方程
    int i=1,j=1,k,r,c;
    while(i<=m && j<=n){//处理第i个方程,第j个未知数
        r=i;//找绝对值最大的系数,防止除数为0,并使得其他方程组系数不会太大
        for(k=i+1;k<=m;k++)if(fabs(A[k][j])>fabs(A[r][j]))r=k;
        if(fabs(A[r][j])>=eps){
        //为0时,说明此项已被消掉,直接算下一未知数,方程不变,不过一般来说跳过的这个元素没有固定解
            for(c=1;c<=n+1;c++)swap(A[i][c],A[r][c]);//交换
            for(k=i+1;k<=m;k++)
                if(fabs(A[k][j])>=eps){
                double f=A[k][j]/A[i][j];
                for(c=j;c<=n+1;c++)//当前方程j前面的系数都是0
                    A[k][c]-=f*A[i][c];
            }
            i++;//获取下一个方程
        }
        j++;//去消下一个未知数
    }
    //必须先判无解再判断多解
    for(k=i;k<=m;k++)if(fabs(A[k][n+1])>=eps)return 0;//若有一行系数为0但是不为答案,则无解
    if(i<=n)return 2;//如处理出的方程没有n个,则为多解。(i=n表示解决了n-1个方程)
    for(int i=n;i>=1;i--){
        for(j=i+1;j<=n;j++)
            A[i][n+1]-=A[i][j]*x[j];
        x[i]=A[i][n+1]/A[i][i];
    }
    //最终统计出的答案x[i]对应第i个元素,换的只是方程顺序
    return 1;//拥有唯一解
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值