筛素数
int num;
int prime[maxn], sf[maxn];
void shai(int n){
memset(sf, 1, sizeof sf);
sf[1]=sf[0]=0;
for(int i=2; i<=n; i++){
if(sf[i]) prime[++num]=i;
for(int j=1; j<=num; j++){
if(i*prime[j]>maxn) break;
sf[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
如果多次询问区间素数个数显然可以用前缀和优化。
int cnt[maxn];//前缀和
void qzh(int n){
int tot=0;
for(int i=1; i<=n; i++){
if(sf[i]) tot++;
cnt[i]=tot;
}
}
逆元
线性推逆元
p为素数。
(inv[i]=(p-p/i)*inv[p\%i]\%p)
p一定为质数,直接线性推就好了。
#include<bits/stdc++.h>
#define N 3000001
typedef long long ll;
using namespace std;
int inv[N], n, p;
int main(){
scanf("%d%d", &n, &p);
inv[1]=1;
printf("1
");
for(int i=2;i<=n;i++){
inv[i]=(ll)(p-p/i)*inv[p%i]%p;
printf("%d
",inv[i]);
}
return 0;
}
单个逆元求法
(x∗b≡1(mod p)) 注意:被除数与n要求互质。
·若p为素数显然费马小定理。
·用exgcd求解(x*b+y*p=1)。
·根据欧拉公式,(x=b^{phi(n−1)}(mod p))。
费马小定理求模质数意义上的逆元
代码显然。
欧拉定理求模任意数意义上的逆元
筛出欧拉函数。
于是就顺便说一下欧拉函数。
欧拉函数(phi(n))即n以内n的约数的个数。
由欧拉定理:(a^phi(p)≡1(mod p)) 。
显然a的逆元(b=a^{phi(p)-1});
CODE:
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
int a, b;
int phi(int n){//求欧拉函数。
int ans=1;
for(int i=2; i*i<=n; ++i){
if(n%i==0) {
n/=i;
ans*=i-1;
while(n%i==0){
n/=i;
ans*=i;
}
}
}
if(n>1)
ans*=n-1;
return ans;
}
ll ksm(int n, int k){
ll res=1;
while(k){
if(k&1)res=res*n%b;
n=n*n%b;
k>>=1;
}
return res;
}
int main() {
scanf("%d%d", &a, &b);
printf("%d", ksm(a, phi(b)-1));
return 0;
}
奇怪的数
EXCRT
问题
求解同余方程组
(left{egin{aligned}xequiv a_1(mod m_1) quad\ xequiv a_2(mod m_2) quad\ xequiv a_3(mod m_3) quad\ ...quad\xequiv a_k(mod m_k) quadend{aligned} ight.)
其中(m_1,m_2,m_3...m_k)为不一定两两互质的整数, 求(x)的最小非负整数解
求解
假设已经求出前(k-1)个方程组成的同余方程组的一个解为(x)
且有(M=prod_{i-1}^{k-1}m_i)
则前(k-1)个方程的方程组通解为(x+i*M(iin Z))
那么对于加入第(k)个方程后的方程组
我们就是要求一个正整数(t),使得 (x+t*M equiv a_k(mod m_k))
转化一下上述式子得(t*M equiv a_k-x(mod m_k))
对于这个式子我们已经可以通过exgcd求解(t)
若该同余式无解,则整个方程组无解, 若有,则前(k)个同余式组成的方程组的一个解解为(x_k=x+t*M)
所以整个算法的思路就是求解(k)次扩展欧几里得