刚看到一些东西,先记下来
持续更新,已经不止标题上面的那三个内容了。
a^-1表示a的逆元
a^2 ≡ b^2 (mod p), so a ≡ b (mod p)//这东西其实就是二次剩余,下面有;可以写一下cf447E
a ≡ b (mod p), so b ≡ a (mod p)
a ≡ b (mod p), so 1/b ≡ a^-1 (mod p)
a ≡ b (mod p), so a/c ≡ b*c^-1 (mod p)
a ≡ b (mod p), so -a ≡ mod-b (mod p)
取模
void Add(LL &x, LL y){
x += y; if(x>=mod)x-=mod;
}
void Sub(LL &x, LL y){
x = x + mod - y; if(x>=mod)x-=mod;
}
void Mul(LL &x, LL y){
x *= y; if(x>=mod)x%=mod;
}
(a / b) % p = (a % (p*b)) / b
a
b
m
o
d
p
=
d
\frac{a}{b}\;\;mod\;\;p\;=\;d
bamodp=d
a
b
=
p
x
+
d
\frac{a}{b}\;\; =\;px + d
ba=px+d
a
=
p
b
x
+
b
d
a\;=\;pbx + bd
a=pbx+bd
a
m
o
d
p
b
=
b
d
a\;mod\;pb\;=\;bd
amodpb=bd
a
m
o
d
p
b
b
=
d
\frac{a\;mod\;pb}{b}\;=\;d
bamodpb=d
a
b
m
o
d
p
=
a
m
o
d
p
b
b
\frac{a}{b}\;\;mod\;\;p\;=\;\frac{a\;mod\;pb}{b}
bamodp=bamodpb
同余, CRT
x = sigma (ri*(M/ai)*inv(M/ai,ai)) % MOD
N ≡ r1(mod a1) N ≡ r2(mod a2)...
考虑前两个式子N = r1+a1*x = r2+a2*y --> a1*x - a2*y = r2-r1 = R
a1/gcd*x=R/gcd+a2/gcd*y,也就是a1/gcd*x≡R/gcd mod(a2/gcd)
由exgcd(a1/gcd,a2/gcd,d',X,Y)得到a1/gcd*X+a2/gcd*Y=1的一组解(X,Y)
X = inv(a1/gcd,a2/gcd)
x ≡ X*(R/gcd) mod(a2/gcd) -> x ≡ (R/gcd)*X+t*(a2/gcd)
回代到第一个式子:N = X*(R/gcd)*a1+r1+t*a1*a2/gcd
化简:N ≡ X*(R/gcd)*a1+r1 mod(a1*a2/gcd)
得到新的方程式:r1 = a1*X*R/gcd + r1, a1 = a1*a2/gcd
int CRT(){
int flag=0,a1=ar[1],r1=r[1],R,d,x,y,dm;
for(int i=2;i<=n;++i){
exgcd(a1,ar[i],d,x,y);
R=r[i]-r1;
if(R%d){flag=1;break;}
dm=ar[i]/d;
x=((x*R/d)%dm+dm)%dm;
r1=a1*x+r1;a1=a1*dm;
}
return r1;
}
逆元
以下两种方法必须满足
a
a
a与
p
p
p互质才能求出逆元
a
×
b
≡
1
(
m
o
d
p
)
a \times b ≡ 1\;(mod\;p)
a×b≡1(modp)称
a
,
b
a, b
a,b互为模
n
n
n意义下的逆元。
x
/
a
=
x
×
b
%
p
x/a=x\times b\%p
x/a=x×b%p
容易得到:
a
×
b
+
k
×
p
=
1
a\times b+k\times p=1
a×b+k×p=1,由
e
x
g
c
d
exgcd
exgcd可以轻松得到
a
a
a的逆元。
费马小定理
若p为素数,则 a^(p-1) = 1 (mod p)
a * a^(p-2) = 1 (mod p)
a 的逆元 = a^(p-2) % p
ϕ(p) = p - 1
当x≥ϕ(p)时,有a^x ≡ a^(x mod ϕ(p)+ϕ(p)) mod p
gcd(a,mod)=1 a^(x) = a^(x%ϕ(mod)) % mod
if x>=ϕ(mod) && gcd(a,mod)!=1 a^(x) = a^(x%ϕ(mod) + ϕ(mod)) % mod
if x<ϕ(mod) && gcd(a,mod)!=1 a^(x) = a^(x%ϕ(mod)) % mod
欧拉定理:若a, p互素, a^ϕ(p) = 1(mod p), a模p意义下的逆元 = a^(ϕ(p) - 1)
void exgcd(int a,int b,int &d,int &x,int &y){
if(b == 0){
x = 1; y = 0; d = a;
return;
}
exgcd(b, a % b, d, y, x);
y -= a / b * x;
}
a的逆元 = (x % mod + mod) % mod
预处理x的逆元
void getinv(){//mod为素数
inv[1] = 1;
for(int i = 2; i < N; ++i)
inv[i] = (MOD-MOD/i) * 1LL * inv[MOD%i] % MOD;
}
LL inv(LL t, LL p){//求t关于p的逆元
return t==1?1: (p-p/t) * inv(p % t, p) % p;
}
预处理x!的逆元
LL ksm(LL a, int b) {
LL res = 1;
for(; b; b>>=1, a=a*a%mod) {
if(b&1) res = res * a % mod;
}
return res;
}
const int MAXN = 1e6 + 6;
LL F[MAXN], invF[MAXN];
void init_comb() {
F[0] = 1;
for (int i = 1; i < MAXN; i++) F[i] = F[i - 1] * i % mod;//阶乘
invF[MAXN - 1] = ksm(F[MAXN - 1], mod - 2);
for (int i = MAXN - 2; i >= 0; i--) invF[i] = invF[i + 1] * (i + 1) % mod;//阶乘的逆元
}
LL COMB(int n, int m) {//组合数
if(n < m) return 0; if(n == m)return 1;
return F[n] * invF[m] % mod * invF[n-m] % mod;
}
const int MAXN = 1e6 + 6;
LL fac[MAXN], facInv[MAXN], inv[MAXN];
void init_comb() {
inv[1] = 1;//逆元
fac[0] = facInv[0] = 1;//阶乘和阶乘的逆元
for(int i = 1; i < MAXN; ++i) {
if(i != 1) inv[i] = (mod - mod / i)*inv[mod % i] % mod;
fac[i] = fac[i-1] * i % mod;
facInv[i] = facInv[i-1] * inv[i] % mod;
}
}
LL COMB(int n, int m) {//组合数
if(n < m) return 0; if(n == m)return 1;
return fac[n] * facInv[m] % mod * facInv[n-m] % mod;
}
这里还有很多东西:here
gcd && Exgcd
void exgcd(LL a, LL b, LL &d, LL &x, LL &y) {
if(b == 0){
x = 1; y = 0; d = a;
return;
}
exgcd(b, a % b, d, y, x);
y -= a / b * x;
return;
}
反素数
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL pp[16] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
LL ans, n, MAXY;
//求n以内因子最多的数,多个答案输出小的
void dfs(LL Y, LL dep, LL num, LL limit){
//因子数 深度 当前的数
if(dep == 16)return;
//if(Y >= n) return;//n个因数的最小整数
if(Y > MAXY) MAXY = Y, ans = num;
if(Y == MAXY) ans = min(ans, num);
for(int i = 1; i <= limit; ++i){
//因为后面的次数不会超过前面,所以这里添加上限就是一个极大的剪枝
if(n / pp[dep] < num) break;//保证不超过n
dfs(Y*(i+1), dep+1, num*=pp[dep], i);
}
}
int main(){
int tim; scanf("%d", &tim);
while(tim --){
scanf("%lld",&n);
ans = 1e18;
MAXY = 0;
dfs(1, 0, 1, 60);
printf("%lld %lld\n", ans, MAXY);
}
}
二次剩余
记一些结论及方法,不做证明(因为不会
定义:若方程
x
2
≡
a
(
m
o
d
p
)
x^2≡a(mod\;p)
x2≡a(modp)有解,则称
a
a
a为模
p
p
p的二次剩余;反之称为
a
a
a为模
p
p
p的非二次剩余。
称
x
x
x为二次同余方程的解。
因此:由 x 2 ≡ a ( m o d p ) x^2≡a(mod\;p) x2≡a(modp)可以推出 x ≡ a ( m o d p ) x≡\sqrt a(mod\;p) x≡a(modp)。 a a a可以模p的意义下开根号。
勒让德符号:
(
n
p
)
=
{
1
n为模p的二次剩余
−
1
n为模p的非二次剩余
0
a≡0(mod
p)
(\frac{n}{p})= \begin{cases} 1& \text{n为模p的二次剩余}\\ -1& \text{n为模p的非二次剩余}\\ 0& \text{a≡0(mod\;p)} \end{cases}
(pn)=⎩
⎨
⎧1−10n为模p的二次剩余n为模p的非二次剩余a≡0(modp)
欧拉判别法:
(
n
p
)
=
a
p
−
1
2
(
m
o
d
p
)
(\frac{n}{p})=a^{\frac{p-1}{2}}(mod\;p)
(pn)=a2p−1(modp)
定理1:
x
2
≡
a
(
m
o
d
p
)
x^2≡a(mod\;p)
x2≡a(modp)共有
p
−
1
2
+
1
\frac{p-1}{2}+1
2p−1+1个
n
n
n的值使得方程有解。其中
+
1
+1
+1代表
n
=
0
n=0
n=0的情况。
定理2:
(
a
+
b
)
p
≡
a
p
+
b
p
(
m
o
d
p
)
(a+b)^p≡a^p+b^p(mod\;p)
(a+b)p≡ap+bp(modp)
证明:通过二项式展开可以得到:
(
a
+
b
)
p
=
∑
k
=
0
p
C
p
k
a
k
b
p
−
k
(a+b)^p=\sum_{k=0}^{p}C_{p}^{k}a^kb^{p-k}
(a+b)p=∑k=0pCpkakbp−k。
当
k
k
k不等于
p
p
p且不为
0
0
0时,
C
p
k
C_{p}^{k}
Cpk中的
p
p
p是不可能被消掉的,于是就会在取模时被消掉。
Cipolla算法:
设
a
满足
ω
=
a
2
−
n
是模
p
的非二次剩余,即
x
2
≡
ω
(
m
o
d
p
)
无解。那么
x
=
(
a
+
ω
)
p
+
1
2
是二次同余方程
x
2
=
n
(
m
o
d
p
)
的解。
设a满足\omega =a^2-n是模p的非二次剩余,即x^2≡\omega(mod\;p)无解。那么x=(a+\sqrt \omega)^{\frac{p+1}{2}}是二次同余方程x^2=n(mod\;p)的解。
设a满足ω=a2−n是模p的非二次剩余,即x2≡ω(modp)无解。那么x=(a+ω)2p+1是二次同余方程x2=n(modp)的解。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define random(a,b) (rand()%(b-a+1)+a)
LL quick_mod(LL a, LL b, LL c) { LL ans = 1; while (b) { if (b % 2 == 1)ans = (ans*a) % c; b /= 2; a = (a*a) % c; }return ans; }
LL p;
LL w;//二次域的D值
bool ok;//是否有解
//二次域
struct QuadraticField {
LL x, y;
//二次域乘法重载
QuadraticField operator*(QuadraticField T) {
QuadraticField ans;
ans.x = (this->x*T.x%p + this->y*T.y%p*w%p) % p;
ans.y = (this->x*T.y%p + this->y*T.x%p) % p;
return ans;
}
//二次域快速幂
QuadraticField operator^(LL b) {
QuadraticField ans;
QuadraticField a = *this;
ans.x = 1;
ans.y = 0;
while (b) {
if (b & 1) {
ans = ans*a;
b--;
}
b /= 2;
a = a*a;
}
return ans;
}
};
//求勒让德符号
LL Legender(LL a) {
LL ans=quick_mod(a, (p - 1) / 2, p);
if (ans + 1 == p)//如果ans的值为-1,%p之后会变成p-1。
return -1;
else
return ans;
}
//根据随机出来a的值确定对应w的值
LL Getw(LL n, LL a) {
return ((a*a - n) % p + p) % p;//防爆处理
}
LL Solve(LL n) {
LL a;
if (p == 2)//当p为2的时候,n只会是0或1,然后0和1就是对应的解
return n;
if (Legender(n) == -1)//无解
ok = false;
srand((unsigned)time(NULL));
//随机a的值直到有解
while (1) {
a = random(0, p - 1);
w = Getw(n, a);
if (Legender(w) == -1)
break;
}
QuadraticField ans,res;
res.x = a;
res.y = 1;//res的值就是a+根号w
ans = res ^ ((p + 1) / 2);
return ans.x;
}
int main() {
LL n,ans1,ans2;
while (scanf("%lld%lld",&n,&p)!=EOF) {
ok = true;
n %= p;
ans1 = Solve(n);
ans2 = p - ans1;//一组解的和是p
if (!ok) {
printf("No root\n");
continue;
}
if (ans1 == ans2)
printf("%lld\n", ans1);
else
printf("%lld %lld\n", ans1, ans2);
}
}
欧拉降幂
a^φ(m)≡1(mod m) gcd(a,m)=1
gcd(a,mod)=1 a^(x)=a^(x%ϕ(mod)) %mod
gcd(a,mod)!=1 a^(x)=a^(x%ϕ(mod)+ϕ(mod)) %mod only if x>=ϕ(mod)
gcd(a,mod)!=1 a^(x)=a^(x%ϕ(mod)) %mod only if x<ϕ(mod)
广义二项式定理
单纯的记一下而已。
推论1:当 ∣ x ∣ < 1 |x|<1 ∣x∣<1时,有 1 1 + x = ∑ k = 0 ∞ ( − 1 ) k x k \frac{1}{1+x}=\sum_{k=0}^{∞}(-1)^kx^k 1+x1=∑k=0∞(−1)kxk
推论2:当 ∣ x ∣ < 1 |x|<1 ∣x∣<1时,有 1 1 − x = ∑ k = 0 ∞ x k \frac{1}{1-x}=\sum_{k=0}^{∞}x^k 1−x1=∑k=0∞xk
推论3:当 ∣ x ∣ < 1 |x|<1 ∣x∣<1时,有 1 + x = 1 + ∑ k = 1 ∞ ( − 1 ) k − 1 2 2 k − 1 k ( k − 1 2 k − 2 ) x k \sqrt{1+x}=1+\sum_{k=1}^{∞}\frac{(-1)^{k-1}}{2^{2k-1}k}(_{k-1}^{2k-2})x^k 1+x=1+∑k=1∞22k−1k(−1)k−1(k−12k−2)xk
解决一类离散对数问题
https://blog.csdn.net/qq_18869763/article/details/99004531