数论
辗转相除法与同余系
裴蜀定理:对任何 a , b ∈ Z a,b\in Z a,b∈Z和它们的最大公约数 d d d,关于未知数 x , y x,y x,y的线性不定方程(称为裴蜀等式): a x + b y = c ax+by=c ax+by=c当仅当 d ∣ c d\mid c d∣c,可知有无穷多解。特别地, a x + b y = d ax+by=d ax+by=d一定有解。
推论: a , b a,b a,b互质的充要条件是 a x + b y = 1 ax+by=1 ax+by=1有整数解。
ll gcd(ll a,ll b)//a、b的最大公约数
{
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b)//a、b的最小公倍数
{
return a/gcd(a,b)*b;
}
ll gcd(ll a,ll b,ll &x,ll &y)//扩展欧几里得,引用返回a*x+b*y=gcd(a,b)绝对值之和最小的解
{
if(!a)return x=0,y=1,b;
ll d=gcd(b%a,a,y,x);
return x-=y*(b/a),d;
}
同余系运算
求乘法逆元的另外一种方法是用欧拉定理 x ϕ ( m ) ≡ 1 ( m o d m ) x^{\phi(m)}\equiv1\pmod m xϕ(m)≡1(modm),x的逆是 x ϕ ( m ) − 1 x^{\phi(m)-1} xϕ(m)−1。特别地,m为素数时 ϕ ( m ) = m − 1 \phi(m)=m-1 ϕ(m)=m−1,此时x的逆就是pow(x,m-2,m)
。
log函数:m为素数时求解模方程 a x ≡ b ( m o d m ) a^x\equiv b\pmod m ax≡b(modm)。设P为质数,G为P的原根,则 x y ≡ b ( m o d P ) x^y\equiv b\pmod P xy≡b(modP)等价于 y i n d x ≡ b ( m o d P − 1 ) y\ ind\ x\equiv b\pmod{P-1} y ind x≡b(modP−1),其中 G i n d x ≡ x ( m o d P ) G\ ind\ x\equiv x\pmod P G ind x≡x(modP)。
ll add(ll a,ll b,ll m)
{
if(a+=b,a<0)a=m-(-a%m);//负数取模和编译器有关,这样才是需要的同余系运算
return a%m;
}
ll mul(ll a,ll b,ll m)//根据a*b是否爆ll替换a*b%m
{
ll r=0;
for(a%=m; b; b>>=1,a=add(a,a,m))
if(b&1)r=add(r,a,m);
return r;
}
ll pow(ll a,ll b,ll m)
{
ll r=1;
for(a%=m; b; b>>=1,a=mul(a,a,m))
if(b&1)r=mul(r,a,m);
return r;
}
ll sub(ll a,ll b,ll m)
{
return add(a,-b,m);
}
ll inv(ll a,ll m)//模m下a的乘法逆元,不存在返回-1(m为素数时a不为0必有逆元)
{//return pow(a,phi(m)-1,m);
ll x,y,d=gcd(a,m,x,y);
return d==1?(x+m)%m:-1;
}
ll div(ll a,ll b,ll m)
{
return mul(a,inv(b,m),m);
}
ll log(ll a,ll b,ll m)
{
ll n=ceil(sqrt(m+0.5));
map<ll,ll> x;
for(ll i=0,e=1; i<n; e=mul(e,a,m),++i)
if(!x.count(e))x[e]=i;
for(ll i=0,v=inv(pow(a,n,m),m); i<n; ++i,b=mul(b,v,m))
if(x.count(b))return i*n+x[b];
return -1;
}
同余方程
void sol(ll a,ll b,ll n,vector<ll> &ans)//返回ax=b(mod n)循环节内所有解
{
ll x,y,d=gcd(a,n,x,y);
if(ans.clear(),b%d)return;
ans.push_back((b/d)%(n/d)*(x=(x%n+n)%n));
for(int i=1; i<d; ++i)
ans.push_back((ans[0]+i*n/d)%n);
}
同余方程组
ll sol(const vector<pair<ll,ll> > &v)//x%v[i].first==v[i].second,不存在返回-1
{
ll m=v[0].first,r=v[0].second,c,d,x,y,z;
for(int i=1; i<v.size(); ++i)
{
if(c=v[i].second-r,d=gcd(m,v[i].first,x,y),c%d)
return -1;
gcd(m/d,z=v[i].first/d,x,y),r+=c/d*x%z*m,r%=m*=z;
}
return r<0?r+m:r;
}
欧拉筛
欧拉函数 ϕ ( n ) \phi(n) ϕ(n)是小于n的正整数中与n互素的数的数目。特别地,规定 ϕ ( 1 ) = 1 \phi(1)=1 ϕ(1)=1,易知n>2时都为偶数。
欧拉函数是积性函数,即对任意素数 p , q p,q p,q满足下列关系: ϕ ( p q ) = ϕ ( p ) ϕ ( q ) = ( p − 1 ) ( q − 1 ) \phi(pq)=\phi(p)\phi(q)=(p-1)(q-1) ϕ(pq)=ϕ(p)ϕ(q)=(p−1)(q−1)对任何两个互质的正整数 x , m ( m ≥ 2 ) x, m(m\geq2) x,m(m≥2)有欧拉定理: x ϕ ( m ) ≡ 1 ( m o d m ) x^{\phi(m)}\equiv1\pmod m xϕ(m)≡1(modm)当m为素数p时,此式变为费马小定理: x p − 1 ≡ 1 ( m o d p ) x^{p-1}\equiv1\pmod p xp−1≡1(modp)利用欧拉函数和它本身不同质因数的关系,用筛法 O ( N ) O(N) O(N)预处理某个范围内所有数的欧