版权声明:虽然我只是个小蒟蒻但转载也请注明出处哦 https://blog.csdn.net/weixin_42557561/article/details/82315430
【逆元】
若gcd (a,m) = 1,且 ab = 1 (mod m),则称 b 为 a 模 m 意义下的逆元。显然,模意义下的除法可以用乘 逆元来代替。
【三种方法求解】
方法一:利用费马小定理,当 p 为质数,有 a^p−1=1 (mod p)
很容易发现a * a^p-2 = 1(mod p),那么 a 在模 p 意义下的逆元为 a^p-2
然后用快速幂计算即可
板子
int quickpower(int a,int b,int m){
int ans=1;
while(b){
if(b&1) ans=1ll*ans*a%m;
a=1ll*a*a%m;
b>>=1;
}
return ans;
}
inv[i]=quickpower(i,p-2,p);//i的逆元
这道题用前缀积来处理,除的时候乘逆元,否则会出现精度问题,然后稍微注意一下边界情况即可
代码【我又和c++自带的函数重名了??无语】
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define inf 100009
#define p 9973
using namespace std;
int n;
int pmul[inf],ipmul[inf];
char st[inf];
int quickpower(int a,int b,int m){
int ans=1;
while(b){
if(b&1) ans=1ll*ans*a%m;
a=1ll*a*a%m;
b>>=1;
}
return ans;
}
int inv[inf];
int main(){
while(scanf("%d",&n)!=EOF){
int i,j,k;
scanf("%s",st+1);
int len=strlen(st+1);
pmul[0]=1;
ipmul[0]=1;
for(i=1;i<=len;++i){
pmul[i]=1ll*pmul[i-1]*(st[i]-28)%p;
ipmul[i]=quickpower(pmul[i],p-2,p);
}
for(i=1;i<=n;++i){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",1ll*pmul[b]*ipmul[a-1]%p);
}
}
return 0;
}
方法二:扩展欧几里得算法详细戳这儿
把 ax ≡ 1( mod b ) 变为 ax - by = 1 的形式,就可以啦,求出来的 x 就是 a 在模b意义下的逆元了
板子
void exgcd(int a,int b,int &x,int &y){
if(b==0){ x=1;y=0;return;}
ecgcd(b,a%b,y,x);
y-=a/b*x;
}
exgcd(a,b,x,y);//a在模 b 意义下的逆元
x=(x%b+b)%b;
最后这一步是保证 x 为模 b 意义下最小的正整数,学过扩展欧几里得的同学都知道一组合法解x,y,那么 x + t*b 也是合法的,x%b相当于是一直减 b,然后加上 b 是避免出现负数的情况
方法三 :线性筛(这个我不是很会,只能给板子,不好意思啦)
通过递推求1~n的逆元
我们可以通过inv[i]=inv[p%i]*(p-p/i)%p递推得到逆元。适用于n比较小的情况
板子
int inv[N];
void get_inverse(int n, int p) {
inv[1] = 1;
for (int i = 2; i <= n; ++i) {
inv[i] = (p - p / i) * inv[p % i] % p;
}
}