一元线性同余方程组:
x=r[ i ](mod a[ i ])
将两个方程整合成一个,不断整
比如x%8=7,x%11=9 整合成x%88= -57(31)
ll solve(){
ll M=a[1],R=r[1],x,y,d;
for(int i=2;i<=n;i++){
gcd(M,a[i],d,x,y);
if((R-r[i])%d!=0) return -1;
x=(R-r[i])/d*x%a[i];
R-=x*M;
M=M/d*a[i];
R%=M;
}
return (R%M+M)%M; //这句能保证回到正整数
}
中国剩余定理:
与上面条件不同,需要除数数组m[i]两两互质。
ll a[maxn],m[maxn];
ll china(int n, ll* a, ll* m){
ll M = 1, d, y, x = 0;
for(int i = 0; i<n; i++)
M *= m[i];
for(int i = 0; i<n; i++){
ll w = M / m[i];
gcd(m[i], w, d, d, y);
x = (x + y*w*a[i]) % M;
}
return (x+M)%M;
}
欧拉函数phi:
通式:

性质:
积性函数
(对于正整数n的一个函数 f(n),当中f(1)=1且当a,b互质,f(ab)=f(a)f(b))
2.若n是质数p的k次幂,
,因为除了p的倍数外,其他数都跟n互质。

若n为质数则

//用公式求 n 的欧拉函数值
ll eular(ll n){
ll i,j,ans=n;
for(i=2;i*i<=n;i++){
if(n%i==0){
ans=ans/i*(i-1);
while(n%i==0)
n/=i;
}
}
if(n>1)
ans=ans/n*(n-1);
return ans;
}
//线性筛:同时求欧拉函数和质数表
const int MAXN = 10000000;
bool check[MAXN + 10];
ll phi[MAXN + 10], prime[MAXN + 10]; //int数组容易wa
int tot; // 素数个数
void phi_and_prime_table(int N){ //phi[0]=0,prime[0]=2
memset(check, false, sizeof(check));
phi[1] = 1;
tot = 0;
for (int i = 2; i <= N; i++){
if (!check[i]){
prime[tot++] = i;
phi[i] = i - 1;
}
for (int j = 0; j < tot; j++){
if (i * prime[j] > N){
break;
}
check[i * prime[j]] = true;
if (i % prime[j] == 0){
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
else
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
return ;
}
//普通筛,有时甚至比线性筛快
int n,p,tot;
int phi[N],pri[1000005];
bool mark[N];
void getphi(){ //phi[1]=1,pri[1]=2
phi[1]=1;
for(int i=2;i<=n;i++){
if(!mark[i]){phi[i]=i-1;pri[++tot]=i;}
for(int j=1;j<=tot;j++){
int x=pri[j];
if(i*x>n)break;
mark[i*x]=1;
if(i%x==0){phi[i*x]=phi[i]*x;break;}
else phi[i*x]=phi[i]*phi[x];
}
}
}
//单独求欧拉函数,较灵活
int p,pr[N];
bool prime[N];
int k=0;
void isprime(){
int i,j;
memset(prime,true,sizeof(prime));
for(i=2;i<N;i++){
if(prime[i]){
pr[k++]=i;
for(j=i+i;j<N;j+=i)
prime[j]=false;
}
}
}
int phi(int n){
int rea=n,i;
for(i=0;pr[i]*pr[i]<=n;i++){
if(n%pr[i]==0){
rea=rea-rea/pr[i];
while(n%pr[i]==0) n/=pr[i];
}
}
if(n>1)
rea=rea-rea/n;
return rea%p;
}