ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

关于 数论-逆元 的学习

2022-07-18 20:01:36  阅读:155  来源: 互联网

标签:ch 数论 res mo long 学习 int 逆元 MOD


参考教程: (6条消息) 逆元原理详解_跑起来要带风!的博客-CSDN博客

(6条消息) 密码学中模运算的逆元求解_Gardenia Minwentel的博客-CSDN博客_模逆元怎么求

原理

\(a^{m-1}mod m=1modm\)(m为素数)

\(a*a^{m-2}mod m=1modm\)

\(\frac{1}{a}mod m=a^{m-2}mod m\)

详细见:欧拉定理与费马小定理

板子

long long q_pow(long long a,long long b,long long mo){
    long long res = 1;
    while(b){
        if(b&1)res*=a;
        a*=a;
        b>>=1;
        a%=mo;
        res%=mo;
    }
    return res;
}
long long inv(long long a,long long mo){
    return q_pow(a,mo-2,mo);
}

模板题1845 -- Sumdiv (poj.org)

题意:求\(A^B的所有因子的和mod9901\)

分解质因数:\(A=p_1^{x_1}*p_2^{x_2}*...*p_n^{x_n}\)

\(A^B=p_1^{B*x_1}*p_2^{B*x_2}*...*p_n^{B*x_n}\)

$ans =\prod_{i=1}^{n} \sum_{j=0}{B*x_i}p_ij $

$ans = \prod_{i=1}^{n} \frac{p_i^{B*x_i}-1}{p_i-1} $

这里出现了分数,就要求逆元了。

题目的测试数据Detail of message (poj.org)

#include<iostream>
#define int long long
const int MOD = 9901;
long long q_pow(long long a,long long b,long long mo){
    a%=mo;
    long long res = 1;
    while(b){
        if(b&1)res*=a;
        a*=a;
        b>>=1;
        a%=mo;
        res%=mo;
    }
    return res;
}
long long inv(long long a,long long mo){
    return q_pow(a,mo-2,mo);
}
signed main() {
    std::ios::sync_with_stdio(false);
    long long a,b;std::cin>>a>>b;
    long long ans=1;
    for(int i = 2;i*i<=a;i++){
        int cost = 0;
        while(a%i==0){
            cost++;
            a/=i;
        }
        int k = (q_pow(i,b*cost+1,MOD)-1+MOD )%MOD;
        int ny = inv(i-1,MOD);
        if(ny==0)ans=ans*(b*cost%MOD+1)%MOD;//如果逆元不存在
        else ans=(ans*k%MOD)*ny%MOD;
    }
    if(a>1){
         int k = (q_pow(a,b*1+1,MOD)-1+MOD )%MOD;
        int ny = inv(a-1,MOD);
        if(ny==0)ans=ans*(b*1%MOD+1)%MOD;
        else ans=(ans*k%MOD)*ny%MOD;
    }
    std::cout<<ans<<std::endl;
}

逆元递推

\(inv(n!)\equiv \frac{1}{n!}(mod MOD)\)

\(inv(n!)*n \equiv \frac{1}{(n-1)!}(modMOD)\)

\(inv(n!)*n=inv((n-1)!)\)

由此递推式可以得到所有阶乘的逆元。

\(inv(n)=inv(n!)*(n-1)!\)

然后得到所有的n的逆元。

例题P3811 【模板】乘法逆元 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题意:求1到n的所有整数在模质数p意义下的乘法逆元。

由于数据较大,直接挨个求快速幂逆元会TLE,所以要用到上述递推。

//https://www.luogu.com.cn/problem/P3811
#include <bits/stdc++.h>
#define int long long
const int N = 3e6+10;
long long q_pow(long long a,long long b,long long mo){
    long long res = 1;
    while(b){
        if(b&1)res*=a;
        a*=a;
        b>>=1;
        a%=mo;
        res%=mo;
    }
    return res;
}
long long inv(long long a,long long mo){
    return q_pow(a,mo-2,mo);
}
long long jcny[N];
long long jc[N];
signed main() {
    std::ios::sync_with_stdio(false);
    int n,p;std::cin>>n>>p;
    jc[0]=1;
    for(int i=1;i<=n;i++){
        jc[i]=jc[i-1]*i%p;
    }
    jcny[n]=inv(jc[n],p);
    for(int i=n-1;i>=1;i--){
        jcny[i]=jcny[i+1]*(i+1)%p;
    }
    for(int i=1;i<=n;i++){
        std::cout<<jcny[i]*jc[i-1]%p<<"\n";
    }
}

刷题喽:

P4902 乘积 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这题卡常了,用上快读能快3倍

快读板子:

inline int read() {
    #define reg register
    reg int s = 0, t = 0; reg char ch = getchar();
    while(ch > '9' || ch < '0') t |= ch == '-', ch = getchar();
    while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return t ? -s : s;
}
#include <bits/stdc++.h>
#define int long long
const int MOD = 19260817;
const int mo = MOD;
const int N = 1e6+10;
//long long ans[N],a[N];
inline long long q_pow(long long a,long long b){
    long long res = 1;
    while(b){
        if(b&1)res*=a;
        a*=a;
        b>>=1;
        a%=mo;
        res%=mo;
    }
    return res;
}
inline long long inv(long long a){
    return q_pow(a,mo-2);
}
#define reg register
#define space putchar(' ')
#define enter putchar('\n')
#define pin(a) printf("%d", a)
inline int read() {
    reg int s = 0, t = 0; reg char ch = getchar();
    while(ch > '9' || ch < '0') t |= ch == '-', ch = getchar();
    while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return t ? -s : s;
}
int d[N],hd[N],ans[N];
void init(int n){
	for(int i=1;i<=n;++i)
		hd[i]=1;
	for(int i=1;i<=n;++i)
		for(int j=i;j<=n;j+=i){
			d[j]++;
			hd[j]=hd[j]*i%MOD;
		}
	int tot=1,f=0,g=1,h=1;
	ans[0]=1;
	for(int i=1;i<=n;++i){
		f=(f+d[i])%MOD;
		h=h*hd[i]%MOD;
		g=g*h%MOD;
		tot=tot*q_pow(i,f)%MOD;
		ans[i]=tot*inv(g)%MOD;
	}
}
signed main() {
    std::ios::sync_with_stdio(false);
    init(1e6);
    int t;t=read();
    while(t--){
        int a,b;a=read();b=read();
        std::cout<<ans[b]*inv(ans[a-1])%MOD<<"\n";
    }
}

标签:ch,数论,res,mo,long,学习,int,逆元,MOD
来源: https://www.cnblogs.com/wtn135687/p/16491784.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有