-----(1)欧拉函数:求不大于一个数的与其互质的数的个数
1.如果只用求一个数的话
int phi(int x){
int res=x;
for(int i = 2; i <= x ; i++){
if(x%i == 0){
res=res/p*(p-1);
while(x%i == 0)
x/=i;
}
}
if(x>1) res=res/x*(x-1);
return res;
}
2.如果想要表示所有的话
#include <iostream>
using namespace std;
const int N = 1e6+10;
int primes[N],cnt=0;
int euler[N];
bool st[N];
void get_euler(){
euler[1]=1;
for(int i = 2; i <= n ; i++){
if(st[i]){
primes[cnt++]=i;
euler[i]=i-1;
}
for(int j = 0 ; primes[j]<=n/i; j++){
int t=primes[j]*i;
if(i%primes[j] == 0){
euler[primes[j]*i]=primes[j]*euler[i];
break;
}
else{
euler[primes[j]*i]=euler[i]*(primes[j]-1);
}
}
}
}
------(2).欧几里得算法
int gcd(int a, int b){
if(!b) return a;
return gcd(b,a%b);
}
int exgcd(int a,int b,int &x,int &y){///扩展欧几里得算法
if(!b){
x=1,b=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y -= a/b*x;
return d;
}
---------4.线性同余方程
其与扩展欧几里得其实是同一个式子
所以只需要在用扩展欧几里得算法求出Xo,Yo之后都乘c/gcd(a,b)
!!!这里有一个大坑:
求出X后则真正的Xo应该是Xo*(c/gcd(a,b))不能写成Xo/gcd(a,b)*c
最好写成 c/gcd(a,b)*Xo
有一些细节需要注意:
1.需要判断是否有解
c%d!=0则无解
2.当gcd(a,b)==1时方程在[0,b-1] 有唯一的解,gcd(a,b)==d时在[0,b/d-1]有唯一的解,所以要求最小非负整数时,模的余数变一下
ll EXGCD(ll a,ll b,ll &x,ll &y){
if(!b){
x=1,y=0;
return a;
}
ll d=EXGCD(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main()
{
d=EXGCD(a,b,X,Y),r=b/d;
X=(X*(x-y)/d%r+r)%r;
}
void EXGCD(ll a, ll b, ll &x, ll &y){
if(b == 0){
x=1,y=0;return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
int main()
{
while(cin >> n){
ll m=1,ans=0;
for(int i = 1 ; i <= n ; i++){
cin >> m[i] >> a[i];
M*=m[i];
}
for(int i =1 ; i <= n ; i++){
ll Mi=M/m[i];
ll x,y;
EXGCD(Mi,m[i],x,y);
ans=(ans+a[i]*Mi*x)%MOD;
}
return (ans+MOD)%MOD;
}
return 0;
}
2.一般情况
#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
const int N =1e5+10;
typedef long long ll;
ll m[N],r[N];
int n;
ll EXGCD(ll a, ll b, ll &x, ll &y){
if(!b){
x=1,y=0;
return a;
}
ll d=EXGCD(b,a%b,y,x);
y -= a/b*x;
return d;
}
ll solve(){
ll M=m[1],R=r[1],x,y,d;
for(int i = 2 ; i <= n ; i++){
d=EXGCD(M,m[i],x,y);
if((r[i]-R)%d) return -1;
x=(r[i]-R)/d*x%(m[i]/d);
R+=M*x;
M=M/d*m[i];
R=R%M;
}
return R > 0? R: R+M;
}
int main()
{
while(scanf("%d",&n)!=EOF){
for(int i = 1 ; i <= n ; i++){
scanf("%lld %lld",&m[i],&r[i]);
}
printf("%lld\n",solve());
}
return 0;
}
------6求素数个数
埃氏筛 O (nlogn)
int primes[N],cnt=0;
bool st[N];
void get_primes(int n){
st[0]=st[1]=1;
for(int i = 2; i <= n ; i++){
if(st[i]) continue;
primes[cnt++]=i;
for(int j = 2*i; j <= n ; j+=i){
st[j]=true;
}
}
}
线性筛(欧拉筛)O (n)
int primes[N],cnt=0;
bool st[N];
void get_primes(int n){
for(int i = 2 ; i <= n ; i++){
if(!st[i]) primes[cnt++]=i;
for(int j = 0 ; primes[j]<=n/i && j < cnt ; j++){
st[primes[j]*i]=true;
if(i%primes[j] == 0)break;
}
}
}
-----7组合数
2.线性递推阶乘逆元求组合数
!!! 注意可以的条件是: MOD>max(n,m)
不然就每一个要找的数都求一下逆元
ll inv[N],fac[N];
ll ksm(ll a, ll b){
ll res=1;
a=a%MOD;
while(b){
if(b&1) res=res*a%MOD;
a=a*a%MOD;
b >>= 1;
}
return res;
}
void init(){
fac[0]=1;
for(int i = 1 ; i <= N ; i++) fac[i]=fac[i-1]*i%MOD;
inv[N-1]=ksm(fac[N-1],MOD-2);
for(int i=N-2; i>= 0 ; i--) inv[i]=inv[i+1]*(i+1);
}
ll c(ll n,ll m){
if(m>n) return 0;
return fac[n]*inv[n-m]%MOD*inv[m]%MOD;
}