记录平时遇到的一些知识点。
原根
-
阶:设(a,p)是整数且互质,那么满足(a^n=1mod p)的最小整数(n)就称为(a)模(p)的阶。
-
原根:当(a)模(m)的阶为(varphi(m))时,就称(a)为模(m)的一个原根。
-
性质:假设(g)为模(m)的一个原根,那么满足(g^1,g^2,cdots,g^{p-1})模(m)的结果两两不相同。
-
模(m)有原根的充要条件:(m=2,4,p^a,p^{2a}),(p)为奇素数。
-
快速求原根:得到(m-1)的所有质因子(p_1,p_2,cdots,p_k),从小到达枚举(i),若满足(i^frac{m-1}{p_j}mod m =1),则(i)不为原根。证明可通过裴蜀定理来证明,详见:传送门
二次剩余
- 定义:若存在一个(x),满足(x^2=dmod p),则称(d)为模(p)的二次剩余。
- 勒让德记号:(ig(frac{a}{p}ig)),表示(a^frac{p-1}{2})。
- 欧拉准则:
证明可参见:传送门
- 特别地,若满足(pmod 3equiv4),那么(x^2equiv dmod p)的解为(x=pm d^{frac{p+1}{4}}).
- 更多可参见:wiki
- 二次互反律:
- (left(frac{q}{p} ight)left(frac{p}{q} ight)=(-1)^{frac{(p-1)(q-1)}{4}}),其中(p,q)为两个奇质数;
- 满足:(left(frac{ab}{p} ight)=left(frac{a}{p} ight)left(frac{b}{p} ight));
- 同时,二次互反律还可以用来判断(xequiv pmod q)及(xequiv qmod p)可解的简单关系;
- 其它形式:(left(frac{q}{p} ight)=left(frac{p}{q} ight)(-1)^{frac{(p-1)(q-1)}{4}});
- 如果(aequiv b),则有(left(frac{a}{p} ight)=left(frac{b}{p} ight));
- 运用二次互反律可以将模数较大的判断是否存在二次剩余的情况拆成模数较小的情况,简化运算;
- 辅助定理:(left(frac{2}{p} ight)=(-1)^{frac{p^2-1}{8}},left(frac{-1}{p} ight)=(-1)^{frac{p-1}{2}}).
- 更多可参见:wiki
代码:
Code
//求解x^2=n(mod p)
const int moder = (int) 1e9 + 7;
const int inv2 = (moder + 1) / 2;
struct field2{
int x, y, a, p;
field2():x(0), y(0), a(0), p(0){}
field2(int x, int y, int a, int p):x(x), y(y), a(a), p(p){}
field2 operator *(const field2 &f)const{
int retx = (1ll * x * f.x + 1ll * y * f.y % p * a) % p;
int rety = (1ll * x * f.y + 1ll * y * f.x) % p;
return field2(retx, rety, a, p);
}
field2 powermod(int exp)const{
field2 ret(1, 0, a, p), aux = *this;
for ( ; exp > 0; exp >>= 1){
if (exp & 1){
ret = ret * aux;
}
aux = aux * aux;
}
return ret;
}
};
int powermod(int a, int exp, int moder){
int ret = 1;
for ( ; exp; exp >>= 1){
if (exp & 1){
ret = 1ll * ret * a % moder;
}
a = 1ll * a * a % moder;
}
return ret;
}
int randint(int n){
return rand() % n;
}
vector <int> remain2(int a, int p){ //x^2 = a (mod p)
if (!a || p == 2){ //特判
return {a, a};
}
if (powermod(a, p - 1 >> 1, p) != 1){ //欧拉准则
return {};
}
while (true){
field2 f(randint(p - 1) + 1, randint(p - 1) + 1, a, p);
f = f.powermod(p - 1 >> 1);
if (f.x){
continue;
}
int ret = powermod(f.y, p - 2, p);
return {ret, p - ret};
}
}
斐波那契系数
- 定义:
- 应用:(F^{n-1})的递推系数可由({nkchoose k}_F)确定,但需要注意符号。
- 更多可参见:wiki
高斯二次项系数
- 定义:
- 记([k]_q=1+q^1+cdots +q^{k-1}),那么有:({mchoose r}_q=frac{[m]_q[m-1]_qcdots [m-r+1]_q}{[1]_q[2]_qdots [r]_q},(rleq m))。
- 组合数中的定义:({mchoose r}_q)的含义为从长度为(m)的串中选出(r)个为(1),其余为(0)的所有排列中的逆序对个数,类似于生成函数,假设最后得到的式子为(1+a_1q^1+cdots a_iq^i + cdots + a_nq^n),那么其含义为逆序对个数为(i)的串共有(a_i)种排列。这个可推广到任意多重集排列。
- 易知当(q=1)时,其等同于普通组合数。
类欧几里得
求(sum_{i=0}^{n}lfloorfrac{ai+b}{c}
floor).
推导过程如下:
- 若(ageq c),那么式子可拆分为:(sum_{i=0}^{n}lfloorfrac{(a\%c)i+b}{c} floor+ilfloorfrac{a}{c} floor),后面部分为等差数列,单独计算即可;
- 若(bgeq c),同理式子拆分为:(sum_{i=0}^{n}lfloorfrac{ai+b\%c}{c} floor+lfloorfrac{a}{c} floor),后面部分直接算即可;
- 现在讨论(a<c,b<c)的情况:
交换求和符号,注意到每次(i)都是从(0)到(n),并且我们让(j)从(0)开始,那么有:
发现后面部分和我们一开始处理的是同一个问题,然后我们递归算下去就行了。
因为每次((a,c))变为了((c,a\%c)),所以复杂度为(O(logn))。
直观点来理解类欧的话,所求式子就是求一条直线为(x,y)轴所围成的梯形内部的整点个数。我们的做法就是首先将直线斜率变平缓,然后变换坐标系...依次处理下去,最后肯定直线斜率会趋近于(0)。
附上模板:
Code
```cpp const int MOD = 1000000007, inv2 = (MOD + 1) / 2; ll f(ll n, ll a, ll b, ll c) { //sum_{i=0}^n (ai+b)/c if(a <= 0) return 0; if(a >= c || b >= c) { return (n * (n + 1) % MOD * inv2 % MOD * (a / c) % MOD + (n + 1) * (b / c) % MOD + f(n, a % c, b % c, c)) % MOD; } ll m = (a * n + b) / c; return (m * n % MOD - f(m - 1, c, c - b - 1, a) + MOD) % MOD; } ```莫比乌斯函数
写在其它随笔里面啦,戳这。
杜教筛
同上,戳这。
min25筛
同上,戳这。
欧拉降幂
公式如下:
(证明并不会)
处理相关问题时,有一种精妙的取模方法,可以避免讨论:
ll MOD(ll a, ll b){return a < b ? a : a % b + b}
求(a^{a^{a^{cdots ^a}}}\%p)代码如下:(注意快速幂部分,如果指数大于(p)了,应当保留一个(p))
Code
ll Mod(ll a, ll b) {
return a < b ? a : a % b + b;
}
int qp(ll a, ll b, ll p) {
int ans = 1;
while(b) {
if(b & 1) ans = Mod(ans * a, p);
a = Mod(a * a, p);
b >>= 1;
}
return ans;
}
int calc(ll a, ll b, ll m) {
if(m == 1 || !b) return 1;
int p = phi[m];
int x = calc(a, b - 1, p);
return qp(a, x, m);
}
证明如下:
不妨(x<y),那么(displaystyle gcd(2^x-1,2^y-1)=gcd(2^x-1,2^y-2^x)=gcd(2^x-1,2^xcdot (2^{y-x}-1)))。
设(d=gcd(2^x-1,2^y-1)),显然(d)为奇数,也就是说(d
ot {|}2^x),那么就有(displaystyle gcd(2^x-1,2^xcdot (2^{y-x}-1))=gcd(2^x-1,2^{y-x}-1))。
也就是说我们可以对指数运用欧几里得算法,那么就有(displaystyle gcd(2^x-1,2^y-1)=gcd(2^0-1,2^{gcd(x,y)}-1)=2^{gcd(x,y)}-1)。
故得证。
然后还有第二个式子:
证明如下:
首先有个引理:
证明就是构造个矩阵:
然后通过(displaystyle A^{m+n}=A^m imes A^n)可得。
还有一个引理:
- 若(m,ngeq 1),那么(f_m|f_{nm})
证明的话我们可以对(n)做归纳来证明,证明的话要用到我们刚刚提到的引理。
然后就开始推式子:
令(n=mk+r),有:
我们可以发现下标也可以运用欧几里得算法,所以(displaystyle gcd(f_m,f_n)=f_{gcd(m,n)})。
还有个推论:
- 若(f_m|f_n),则(m|n)。
证明的话就运用(f_m=gcd(f_m,f_n)=f_{gcd(m,n)}=f_m)。
以上相关证明详见传送门。
组合数一些公式
下面是关于组合数的一些式子:
证明的话可以从组合含义来分析,等式左边就相当于我选择某一个数,然后其余选或者不选两种情况,所以最后的方案就为(ncdot 2^{n-1})。
也可以推式子,不过比较好推:
因为(0cdot {nchoose 0}+ncdot {nchoose n}=ncdot {nchoose 0},1cdot {nchoose 1}+(n-1)cdot {nchoose n-1}=ncdot {nchoose 1})等。
所以(displaystyle 2cdot res = ncdot 2^n),即(displaystyle res=ncdot 2^{n-1})。
下面还有一个式子:
我们可以直接通过组合意义来计算,就相当于会选择两个数出来,其余的任选,此时总方案数即为(ncdot (n-1)cdot 2^{n-2}+ncdot 2^{n-1})。
推式子的话感觉不是很好推?qaq
这个式子应该可以进一步推广:
貌似并不能继续化简。