Acwing进阶课--数论

Acwing进阶课–数论

线性基

线性基:是竞赛中常用来解决子集异或一类题目的算法。
线性基:利用高斯消元求出一组矩阵的

基的性质:(梦回线代

  • 线性基中每个元素的二进制最高位互不相同
  • 线性基的维度 = 矩阵的
  • 向量满秩–> 向量线性无关;向量不满秩–>向量线性相关。

构造线性基:

int k = 0;
    for(int i = 62; i >= 0; i --)
    {
        for(int j = k; j < n; j ++)//找到第i位为1的数,交换至第k行
            if(a[j] >> i & 1) 
            {
                swap(a[k], a[j]);
                break;
            }
        if(!(a[k] >> i & 1)) continue;//第i为全为0
        
        for(int j = 0; j < n; j ++) 
            if((a[j] >> i & 1) && j != k) a[j] ^= a[k];
        
        k ++;
        //当行秩<列秩(数的个数 < 62)时:秩 <= 行秩;k == n+1:时可以直接break;
        //不加这一句话,i也只会枚举63次,多枚举的63-n次循环里面都是“continue”。
        if(k == n) break; 
    }

例题:
异或运算

线性基板子

// int_max   (1 << 31) - 1  取 30
// LL_max   (1 << 63) - 1   取 62
// uLL_max  (1 << 64) - 1   取 63
// 注意求 kth  rank之时必须要提前 rebuild
template<typename T, const size_t len = 62>struct LineBase 
{
    int cnt;
    T d[len + 1], p[len + 1];
    T f[len + 1]; 
    bool zero, build;
    void init() 
    {
        for (int i = 0; i < len + 1; ++ i) d[i] = p[i] = f[i] = 0;
        zero = build = false;
        cnt = 0;
    }
    void insert(T x) 
    {
        for (int i = len; ~i; -- i) 
        {
            if(!((x >> i) & 1)) continue;
            if(!d[i]) 
            {
                d[i] = x;
                ++ cnt;
                return ;
            }
            x ^= d[i];
        }
        zero = true;
    }
	// 判断是否能被异或出来
    bool exist(T x) 
    {
        for (int i = len; ~i; -- i) 
        	if(((x >> i) & 1)) 
            {
                if(d[i]) x ^= d[i];
                else return false;
            }
        return true;
    }
    void rebuild() 
    {
        cnt = 0;
        build = true;
        for (int i = len; ~i; -- i) 
            for (int j = i - 1; ~j; -- j)
                if((d[i] >> j) & 1) d[i] ^= d[j];
        
        for (int i = 0; i <= len; ++ i)
            if(d[i]) p[cnt ++] = d[i];
    }
	//查询异或最大,最小
    T maxx(T res = 0) 
    {
        for (int i = len; ~i; -- i) res = max(res, res ^ d[i]);
        return res;
    }
    T minn() 
    {
        if(zero) return 0;
        for (int i = 0; i <= len; ++ i)
            if(d[i]) return d[i];
        
        return -1;
    }
	//  必须选取
	// 注意题意中是否能不选  能不选则要考虑0
	//  k 名次  (从小到大)
    T query_k(T k) 
    {
        if(!build) rebuild();
        if(k >= (((T)1) << cnt)) return -1; // 无解
        if(!k) return 0;
        T res = 0;
        for (int i = len; ~i; -- i) 
            if((k >> i) & 1) res ^= p[i];

        return res;
    }
    T kmx(T k) 
    {
        if(!build) rebuild();
        if(k <= 0) return -1;
        T num = (((T)1) << cnt);
        if(!zero) -- num;
        return kmn(num - k + 1);
    }
    T kmn(T k) 
    {
        if(!build) rebuild();
        if(k <= 0) return -1;
        return k - zero ? kth(k - zero) : 0;
    }
    // 从小到大排  且要求这个数必须能被线性基异或出来才可以查询rank
    T rank(T x) 
    {
        if(!build) rebuild();
        T res = 0;
        for (int i = cnt - 1; ~i; -- i)
            if(x >= p[i]) 
            {
                res += (((T)1) << i);
                x ^= p[i];
            }
        
        return res + zero;
    }
    // 获取此时能获得的元素的个数
    T checkall() 
    {
        return (((T)1) << cnt) - (!zero);
    }
};

LineBase<LL> t;

斯特林数

第一类斯特林数

这里指的为第一类无符号斯特林数

表示 s ( n , m ) s(n, m) s(n,m) [ n k ] \left[{n \atop k} \right] [kn]
意义第一类斯特林数(斯特林轮换数) [ n k ] \left[{n \atop k} \right] [kn] 表示将 n n n 个两两不同的元素,划分为 k k k个非空圆排列的方案数。

圆排列定义:圆排列是排列的一种,指从 n 个不同元素中取出 m(1≤m≤n)个不同的元素排列成一个环形,既无头也无尾。两个圆排列相同当且仅当所取元素的个数相同并且元素取法一致,在环上的排列顺序一致。

递推式:在这里插入图片描述

性质:

  • 升阶函数的关系: 在这里插入图片描述

  • 在这里插入图片描述

Code:

void init()
{
    s[0][0] = 1;
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= m; j ++) 
            s[i][j] = (s[i - 1][j - 1] + 1ll * (i - 1) * s[i - 1][j]) % mod;
}

第二类斯特林数

表示: S ( n , k ) S(n, k) S(n,k) { n k } \left\{\begin{matrix} n \\ k \end {matrix}\right \} {nk}
意义: 第二类斯特林数(斯特林子集数) { n k } \left\{\begin{matrix} n \\ k \end {matrix}\right \} {nk}表示将 n 个两两不同的元素,划分为 k 个非空子集的方案数。
递推式:
在这里插入图片描述

性质:在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

通项公式:在这里插入图片描述

Code:

void init()
{
    S[0][0] = 1;
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= m; j ++)
            S[i][j] = (S[i - 1][j - 1] + 1ll * j * S[i - 1][j]) % P;
}

两种斯特林数的关系:

在这里插入图片描述
例题:建筑师

生成函数

具体可以参考这篇Blog:生成函数全家桶

本人口胡简述:

  • 将利用组合数求方案数转变为利用多项式求方案数(多项式,函数发展较成熟)。
  • 定义:

任意给定一个无限长的序列: a 0 , a 1 , a 2 , . . . , a n , . . . a_0, a_1, a_2, ... , a_n, ... a0,a1,a2,...,an,...
定义函数 g ( x ) = a 0 x 0 + a 1 x 1 + a 2 x 2 + . . . + a n x n + . . . g(x) = a_0x^0+a_1x^1+a_2x^2+...+a_nx^n+... g(x)=a0x0+a1x1+a2x2+...+anxn+...
这是一个无穷级数,我们一般设 x x x的取值范围为: − 1 < x < 1 -1 < x < 1 1<x<1,因为显然在这范围内,无穷级数收敛,我们就可以在 x → ∞ x \rightarrow \infty x的时候得到该无穷级数的值。
我们称这个函数 g ( x ) g(x) g(x)为序列的生成函数。实际上就是将方案数的序列映射成一个多项式的系数,将计数问题转化为多项式问题。例如我们得到生成函数以后,我们就可以使用求极限,泰勒展开,求导积分…

下面举个例子来更好的理解生成函数

Apple

Problem:有 n n n a p p l e apple apple,每种 a p p l e apple apple都有无限个,求选出 k − 1 k-1 k1 a p p l e apple apple的方案数。

  • 组合数学的解法:

因为每一种 apple 都有无限个,也就是说每一种都可以选择 1 , 2 , 3 , 4 , . . . , n , . . . 1, 2, 3, 4, ... , n, ... 1,2,3,4,...,n,...
设第 i i i a p p l e apple apple a i a_i ai
则: a 1 + a 2 + a 3 + . . . + a n = k a_1 + a_2 + a_3 + ... + a_n = k a1+a2+a3+...+an=k a i ≥ 0 a_i \geq 0 ai0sadf
使用隔板法,隔板法要求 a i ≥ 1 a_i \geq 1 ai1,所以我们设: a i ′ = a i + 1 a_i\prime = a_i + 1 ai=ai+1
代入: a 1 ′ + a 2 ′ + a 3 ′ + . . . + a n ′ = k + n a_1\prime + a_2\prime + a_3\prime + ... + a_n\prime = k + n a1+a2+a3+...+an=k+n a i ′ ≥ 1 a_i\prime \geq 1 ai1
可以看做共有 k + n k + n k+n个小球,我们再小球的间隙里,放置 n − 1 n - 1 n1个隔板,把这 k + n k+n k+n个小球隔开,分为 n n n块,(因为每一块之间至少有一个小球,所以才必须要求 a i ≥ 1 a_i \geq 1 ai1),从前往后依次对应 x 1 ′ , x 2 ′ , . . . , a n ′ x_1\prime, x_2\prime, ..., a_n\prime x1,x2,...,an所分配的小球的个数,即为当前的方案,任意的一种隔板的放置方案,对应着方程组的一组解。
可得答案为: C k + n − 1 n − 1 = C_{k+n-1} ^ {n - 1} = Ck+n1n1= ( k + n − 1 n − 1 ) {k+n-1} \choose {n-1} (n1k+n1)

  • 生成函数的解法:

我们对于第一种 a p p l e apple apple:可以选 0 , 1 , 2 , . . . , n 0,1, 2,...,n 012...n个。
f 1 ( x ) = 1 + x + x 2 + x 3 + . . . f_1(x) = 1 + x + x^2 + x^3 + ... f1(x)=1+x+x2+x3+...
f 1 ( x ) = 1 − x n 1 − x f_1(x) = \frac{1 - x^n}{1-x} f1(x)=1x1xn
lim ⁡ x → ∞ f 1 ( x ) = 1 1 − x \lim_{x \rightarrow\infty} f_1(x) = \frac{1}{1-x} limxf1(x)=1x1
同理: f 2 ( x ) = 1 1 − x f_2(x) = \frac{1}{1-x} f2(x)=1x1 f 3 ( x ) = 1 1 − x f_3(x) = \frac{1}{1-x} f3(x)=1x1,… , f n ( x ) = 1 1 − x f_n(x) = \frac{1}{1-x} fn(x)=1x1
所以最终:
f ( x ) = f 1 ( x ) ∗ f 2 ( x ) ∗ f 3 ( x ) ∗ . . . ∗ f n ( x ) = 1 ( 1 − x ) n f(x) = f_1(x) * f_2(x) * f_3(x) * ... * f_n(x)\\=\frac{1}{(1-x)^{n}} f(x)=f1(x)f2(x)f3(x)...fn(x)=(1x)n1 = a 0 x 0 + a 1 x 1 + a 2 x 2 + . . . + a k x k = a_{0}x^{0} + a_1x^{1} + a_2x^2+...+a_kx^k =a0x0+a1x1+a2x2+...+akxk
其中 a k a_k ak对应我们上面求得的公式:
a k = C k + n − 1 m − 1 a_k = C_{k + n -1} ^ {m-1} ak=Ck+n1m1

结论
1 ( 1 − x ) n \frac{1}{(1-x)^{n}} (1x)n1 x k x^k xk的系数为: C k + n − 1 m − 1 C_{k+n-1}^{m - 1} Ck+n1m1。表示: n n n a p p l e apple apple,个数无限,选 k k k个的方案数。

例题:食物

FFT

这里墙裂安利一片Blog:超简单的快速傅里叶变换!

本人口胡简述:

FFT :快速傅里叶变换。
用于:快速求出两个多项式的乘积(卷积);大数 × \times ×大数(大数快速幂)。

Code:

const int N = 5e5 + 10;
const double PI = acos(-1);

struct Complex
{
	double x, y;
	
	Complex operator + (const Complex &t) const
	{
		return {x + t.x, y + t.y};
	}
	Complex operator - (const Complex &t) const
	{
		return {x - t.x, y - t.y};
	}
	Complex operator * (const Complex &t) const
	{
		return {x * t.x - y * t.y, y * t.x + x * t.y};
	}
}a[N], b[N];

int tot, bit;
int tra[N];//蝴蝶转换

void fft(Complex a[], int type)
{
	for(int i = 0; i < tot; i ++)
		if(i < tra[i]) swap(a[tra[i]], a[i]);//当i<tra[i]时交换:避免数交换两次,以至于没转换。
	
	for(int mid = 1; mid < tot; mid <<= 1)
	{
		auto w1 = Complex({cos(PI / mid), type * sin(PI / mid)});
		for(int pos = 0, len = mid << 1; pos < tot; pos += len)
		{
			auto wk = Complex({1, 0});
			for(int k = 0; k < mid; k ++, wk = wk * w1)
			{
				//左半部分
				Complex x = a[pos + k];
				//右半部分
				Complex y = a[pos + k + mid];
				a[pos + k] = x + wk * y;
				a[pos + k + mid] = x - wk * y;
			}
		}
	}
	if(type == 1) return;
	rep(i, 0, tot) a[i].x /= tot;
}

int main()
{
    ios;
    int n, m;
    cin >> n >> m;
    rep(i, 0, n) cin >> a[i].x;
    rep(i, 0, m) cin >> b[i].x;
    //n, m分别是A多项式,B多项式的最高次
    while((1 << bit) <= n + m) bit ++;
    tot = 1 << bit;
    
	rep(i, 0, tot - 1)//处理转换数组
		tra[i] = ((tra[i / 2] / 2) | (i & 1) << (bit - 1));
    // exit(0);
    
    fft(a, 1), fft(b, 1);
    rep(i, 0, tot) a[i] = a[i] * b[i];
    fft(a, -1);
    
    rep(i, 0, n + m) cout << int(a[i].x + 0.5) << ' ';
    
    return 0;
}

例题:
多项式乘法
大数乘大数
大数快速幂

BSGS 和 扩展BSGS(北上广深)

BSGS(Baby Step Giant Step)

给定正整数 a , b , P a,b,P a,b,P ( a , P ) = 1 即 a , P 互质 (a, P) =1即a,P互质 (a,P)=1aP互质
求满足 a t ≡ b ( m o d   P ) a^t\equiv b(mod\ P) atb(mod P)
最小非负整数 t t t

由于 ( a , P ) = 1 (a, P) = 1 (a,P)=1
⇒ a φ ( P ) ≡ 1   ( m o d   P ) \Rightarrow a^{\varphi(P)} \equiv1\ (mod\ P) aφ(P)1 (mod P),可以看出 a t a^t at在模 P P P意义下的最小循环节为 φ ( P ) \varphi(P) φ(P).
⇒ \Rightarrow 所以我们要找 t t t范围是: t ∈ [ 0   ∼ φ ( P ) ] t\in[0 ~ \sim \varphi(P)] t[0 φ(P)]
⇒ \Rightarrow 扩大范围: t ∈ [ 0 ∼ P ] t\in [0 \sim P] t[0P]
⇒ \Rightarrow 令: k = P + 1 k = \sqrt{P} + 1 k=P +1+1因为计算机开根误差);
⇒ \Rightarrow t = k ∗ x − y t = k*x-y t=kxy x ∈ [ 1 ∼ k ] x\in[1 \sim k] x[1k] y ∈ [ 0 ∼ ( k − 1 ) ] y\in[0\sim(k -1)] y[0(k1)],这里x,y可以看做: x = t / k , y = t % k x=t/k, y=t\%k x=t/k,y=t%k)。
⇒ \Rightarrow t m i n = k − ( k − 1 ) = 1 t_{min} = k - (k-1)= 1 tmin=k(k1)=1 t m a x = k ∗ k = k 2 = P t_{max} = k * k = k ^2 = P tmax=kk=k2=P
⇒ \Rightarrow t ∈ [ 1 ∼ P ] t \in[1\sim P] t[1P]。这里 t t t少一种 0 0 0,故我们应先特判 t = 0 t= 0 t=0的情况。
⇒ \Rightarrow 特判 0 0 0之后,在 x ∈ [ 1 ∼ k ] x\in[1\sim k] x[1k] y ∈ [ 0 ∼ k − 1 ] y \in [0\sim k-1] y[0k1]中找到: t = k ∗ x − y t = k * x - y t=kxy,满足:
a t ≡ b ( m o d   P ) a^t \equiv b (mod\ P) atb(mod P)
⇒ \Rightarrow a k ∗ x − y ≡ b ( m o d   P ) a^{k*x - y} \equiv b (mod\ P) akxyb(mod P)
⇒ \Rightarrow a k ∗ x ≡ b ∗ a y ( m o d   P ) a^{k*x} \equiv b * a^y(mod\ P) akxbay(mod P)
⇒ \Rightarrow 不能二重循环找 x , y x,y x,y,这样为 O ( k 2 = P ) O(k^2 = P) O(k2=P)
⇒ \Rightarrow 对于每一个 x x x y y y都要跑 [ 0 ∼ k − 1 ] [0\sim k-1] [0k1]
⇒ \Rightarrow 先预处理,每一个 y y y对应的 b ∗ a y ( % P ) b*a^y(\%P) bay(%P);再跑 x ∈ [ 1 ∼ k ] x\in [1\sim k] x[1k]判断是否存在 b ∗ a y ( % P ) = a k x ( % P ) b*a^y(\%P) = a^{kx}(\% P) bay(%P)=akx(%P)即可。
⇒ \Rightarrow 时间复杂度: O ( k = P ) O(k = \sqrt{P}) O(k=P

Code:

int a, p, b;

int BSGS(int a, int p, int b)
{
    //特判t=0
    if(1 % p == b % p) return 0;
    
    //t = kx-y。x--[1 ~ k];y--[0 ~ k-1]
    int k = sqrt(p) + 1;
    
    //遍历y,预处理(b*a^y) % p
    unordered_map<int, int> hash;
    for(int i = 0, w = b % p; i <= k - 1; i ++, w = 1ll * w * a % p)
        hash[w] = i;
    
    //求a^k
    int ak = 1; 
    for(int i = 1; i <= k; i ++) ak = 1ll * ak * a % p;
    
    //遍历x
    for(int i = 1, w = ak; i <= k; i ++, w = 1ll * w * ak % p)
        if(hash.count(w)) return (k * i - hash[w]) % p;
    
    return -1;
}

例题:
BSGS
随机数生成器

扩展BSGS

求最小非负整数 t t t,使得 a t ≡ b ( % P ) a^t\equiv b(\% P) atb(%P) a 和 P 不一定互质 a和P不一定互质 aP不一定互质

1:特判 t = 0 t = 0 t=0的情况。
2: t ≥ 1 t \geq 1 t1:

a , P a,P a,P最大公约数: d = ( a , P ) d = (a, P) d=(a,P)
①: a , P 互质 − − d = 1 a, P互质--d = 1 a,P互质d=1。直接BSGS
②: d > 1 d > 1 d>1
a t ≡ b ( % P ) a^t\equiv b(\% P) atb(%P)
⇒ \Rightarrow a t + k P = b ( % P ) a ^ t+kP = b(\% P) at+kP=b(%P)
因为 d d d a a a的约数, d d d P P P的约数;由裴蜀定理得: d d d b b b的约数。
⇒ \Rightarrow 故当 b % d ≠ 0 即 d 不是 b 的约数 b \% d \neq 0即d不是b的约数 b%d=0d不是b的约数;无解。
⇒ \Rightarrow b % d = 0 b \% d = 0 b%d=0
⇒ \Rightarrow a t − 1 ∗ a d + k ∗ p d = b d a^{t-1} * \frac{a}{d} + k * \frac{p}{d} = \frac{b}{d} at1da+kdp=db
⇒ \Rightarrow a t − 1 ∗ a d ≡ b d ( % P d ) a^{t -1} * \frac{a}{d} \equiv \frac{b}{d}(\% \frac{P}{d}) at1dadb(%dP)
⇒ \Rightarrow a t − 1 ≡ P d ∗ i n v ( a d ) [ a b 关于 P d 的逆元 ] ( % P ) a^{t-1} \equiv \frac{P}{d} * inv(\frac{a}{d})[\frac{a}{b}关于\frac{P}{d}的逆元] (\% P) at1dPinv(da)[ba关于dP的逆元](%P)–由于 P d \frac{P}{d} dP不一定是质数,求逆元要用扩展欧几里得
(由于 P P P的因子有限,最多递归 l o g 2 P log_2P log2P次, a t ‘ 与 P ‘ 互质 a^{t`}与P`互质 atP互质,这时直接调用BSGS。)

Code:

int a, p, b;

int exgcd(int a, int b, int &x, int &y)
{
    if(!b)
    {
        x = 1, y = 0;
        return a;
    }
    
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int bsgs(int a, int p, int b)
{
    if(1 % p == b % p) return 0;
    
    int k = sqrt(p) + 1;
    unordered_map<int, int> hash;
    for(int i = 0, w = b % p; i < k; i ++, w = 1ll * w * a % p)
        hash[w] = i;
    
    int ak = 1;
    for(int i = 1; i <= k; i ++) ak = 1ll * ak * a % p;
    
    for(int i = 1, w = ak % p; i <= k; i ++, w = 1ll * w * ak % p)
        if(hash.count(w)) return k * i - hash[w];
    return -1e9;
}

int exbsgs(int a, int p, int b)
{
    //逆元x可能为负,这里的b也可能是负数
    b = (b % p + p) % p;
    if(1 % p == b % p) return 0;
    
    int x, y;
    int d = exgcd(a, p, x, y);
    if(d == 1) return bsgs(a, p, b);
    
    if(b % d) return -1e9;
    //x是(a/d) 关于 (p/d)的逆元,可能为负数
    exgcd(a / d, p / d, x, y);
    return 1 + exbsgs(a, p / d, 1ll * b / d * x % (p / d));
}

int main()
{
    while(cin >> a >> p >> b , a || p || b)
    {
        int res = exbsgs(a, p, b);
        if(res < 0) puts("No Solution");
        else cout << res << endl;
    }
    
    return 0;
}

例题:扩展BSGS

Burnside引理和polya定理

参考资料
主要用来解决 “本质不同” 的计数问题。(如:用m种颜色给立方体,珠链染色)
前置知识:

置换

有限集合到自身的双射(即一一对应)称为置换。集合 S = { a 1 , a 2 , … , a n } S = \{a_1,a_2,\dots,a_n\} S={a1,a2,,an}上的置换可以表示为: f = ( a 1 , a 2 , … , a n a p 1 , a p 2 , … , a p n ) f = \begin{pmatrix}a_1,a_2,\dots,a_n\\a_{p_1},a_{p_2},\dots,a_{p_n}\end{pmatrix} f=(a1,a2,,anap1,ap2,,apn)
意为将 a i a_i ai映射为 a p i a_{p_i} api,其中 p 1 , P 2 , … , p n p_1, P_2, \dots, p_n p1,P2,,pn 1 , 2 , … , n 1, 2, \dots, n 1,2,,n的一个排列。显然 S S S上所有置换的数量为 n ! n! n!

循环置换:

循环置换是一类特殊的置换,可表示为
( a 1 , a 2 , … , a m ) = ( a 1 , a 2 , … , a m − 1 , a m a 2 , a 3 , … , a m , a 1 ) (a_1,a_2,\dots,a_m) = \begin{pmatrix}a_1,a_2,\dots,a_{m-1},a_m\\a_2,a_3,\dots,a_m,a_1\end{pmatrix} (a1,a2,,am)=(a1,a2,,am1,ama2,a3,,am,a1)
若两个循环置换不含有相同的元素,则称它们是不相交的。有如下定理:
任意一个置换都可以分解为若干不相交的循环置换的乘积,例如
( a 1 , a 2 , a 3 , a 4 , a 5 a 3 , a 1 , a 5 , a 4 ) = ( a 1 , a 3 , a 2 ) ∘ ( a 4 , a 5 ) \begin{pmatrix}a_1, a_2,a_3,a_4,a_5\\a_3,a_1,a_5,a_4\end{pmatrix}=(a_1,a_3,a_2)\circ(a_4,a_5) (a1,a2,a3,a4,a5a3,a1,a5,a4)=(a1,a3,a2)(a4,a5)
该定理的证明也非常简单。如果把元素视为图的节点,映射关系为有向边,则每个点的入度个出度都为 1 1 1,因此形成的图形必定是若干个环的集合,而一个环即可用一个循环置换表示。

Burnside 引理

总结版:每种置换的不动点个数的平均值,即为==“本质不同”== 的方案数。

Polya 定理

总结版:引入“循环群”,每种置换都可以拆为多个互不干扰的“循环群”(因为每个点的出度个入度都为1,所以一定是形成多个环),因此每个“循环群的”颜色也是互不干扰的。故:每种置换的不动点 = 颜色种 类 { 该置换可拆为循环群的数量 } = 颜色种类^{\{该置换可拆为循环群的数量\}} =颜色种{该置换可拆为循环群的数量}

可以发现:polya就是找到一种计算Burnside每种置换不动点个数的方法。

  • 注:当置换能分为互不干扰循环群才能进一步使用Polya定理;不然还是要是用Burnside引理!

这里举个例子:

问题:用 M M M种颜色,给 N N N个珠子组成的环形手链染色,有多少中方案。这里要求本质不同的方案数。(即:两种染色方式经旋转翻转能完全重合,则视为同一种手链。)

可以看出存在旋转翻转两种置换,我们分别分析这两种置换:
旋转
我们令其每个点旋转 K K K次即: a i 旋转至 a i + K , ( K ∈ [ 0 ∼ n − 1 ] ) a_i 旋转至 a_{i+K},(K \in [0\sim n-1]) ai旋转至ai+K(K[0n1])
d = g c d ( N , K ) d = gcd(N, K) d=gcd(N,K),可以发现:每个点转 N d \frac{N}{d} dN次,可以回到出发点。

证明:从 i i i出发,每次跳 K K K步,求最小 a a a
要满足: i + a ∗ K ≡ i ( % N ) i + a*K \equiv i(\% N) i+aKi(%N)
⇒ \Rightarrow a ∗ K ≡ 0 ( % N ) a*K\equiv 0(\%N) aK0(%N)
a = N d = g c d ( N , K ) 时: a=\frac{N}{d = gcd(N,K)}时: a=d=gcd(N,K)N时: ⇒ \Rightarrow N ∗ K d ≡ 0 ( % N ) N * \frac{K}{d} \equiv 0(\%N) NdK0(%N),可以发现 N K 与 N 互质 \frac{N}{K}与N互质 KNN互质,此时的 a a a最小。

所以这个置换可以拆分为 N N d = d \frac{N}{\frac{N}{d}} = d dNN=d循环置换,每个循环置换之间的颜色互不干扰。该置换的方案数: M ( n , K ) M^{(n, K)} M(n,K)
旋转置换的方案数为: ∑ K = 0 N − 1 M ( N , K ) \sum\limits_{K = 0}^{N-1}{M^{(N, K)}} K=0N1M(N,K)
翻转

N为偶数

  • 两个点形成一条对称轴: N 2 \frac{N}{2} 2N条,每条对称轴形成 N 2 + 1 \frac{N}{2}+1 2N+1个循环群。
  • 两点之间的空隙形成一条对称轴: N 2 \frac{N}{2} 2N条,每条轴形成 N 2 \frac{N}{2} 2N个循环群。

N为偶数方案数: N 2 ∗ ( M N 2 + M N 2 + 1 ) \frac{N}{2}*(M^{\frac{N}{2}} + M^{\frac{N}{2} + 1}) 2N(M2N+M2N+1)

N为奇数:

  • 每个点形成一条对称轴: N N N条,每条对称轴形成 N + 1 2 \frac{N+1}{2} 2N+1个置换群。

N为奇数方案数: N ∗ M N + 1 2 N * M ^ {\frac{N+1}{2}} NM2N+1

翻转置换方案数为: f ( x ) = { N 为偶数: N 2 ∗ ( M N 2 + M N 2 + 1 ) N 为奇数: N + 1 2 f(x)=\left\{ \begin{aligned} N为偶数:& \frac{N}{2}*(M^{\frac{N}{2}} + M^{\frac{N}{2} + 1}) \\ N为奇数:& \frac{N+1}{2} \\ \end{aligned} \right. f(x)= N为偶数:N为奇数:2N(M2N+M2N+1)2N+1

:当置换没法拆分为互不干扰的置换群时,无法使用Polya定理
例:魔法手链:这里的染色方法有约束,无法将置换拆分为互不干扰的置换群,只能使用Burnside引理。

积性函数

定义:
定义在正整数上的函数, ∀ g c d ( a , b ) = 1 , f ( a , b ) = f ( a ) f ( b ) \forall gcd(a,b) = 1, f(a,b) = f(a)f(b) gcd(a,b)=1,f(a,b)=f(a)f(b)

凡是积性函数均可使用线性筛法来求解。例: μ ( i ∗ p j ) = μ ( i ) ∗ μ ( p j ) = − μ ( i ) , p j 为质数。 \mu (i*p_j) = \mu(i) * \mu(p_j) = -\mu(i),p_j为质数。 μ(ipj)=μ(i)μ(pj)=μ(i)pj为质数。

  • μ ( x ) \mu(x) μ(x)是积性函数。

证明
a = p 1 α 1 × p 2 α 2 × ⋯ × p n α n a = p_{1}^{\alpha1} \times p_{2}^{\alpha2} \times \dots \times p_{n}^{\alpha n} a=p1α1×p2α2××pnαn
b = p 1 β 1 × p 2 β 2 × ⋯ × p n β n b = p_{1}^{\beta1} \times p_{2}^{\beta2} \times \dots \times p_{n}^{\beta n} b=p1β1×p2β2××pnβn
a × b = p 1 α 1 × p 2 α 2 × ⋯ × p n α n × p 1 β 1 × p 2 β 2 × ⋯ × p n β n a \times b = p_{1}^{\alpha1} \times p_{2}^{\alpha2} \times \dots \times p_{n}^{\alpha n} \times p_{1}^{\beta1} \times p_{2}^{\beta2} \times \dots \times p_{n}^{\beta n} a×b=p1α1×p2α2××pnαn×p1β1×p2β2××pnβn

  • μ ( a ) = 0 \mu(a) = 0 μ(a)=0 μ ( b ) = 0 \mu(b) = 0 μ(b)=0,则 μ ( a × b ) = 0 \mu(a \times b) = 0 μ(a×b)=0。即: μ ( a × b ) = μ ( a ) × μ ( b ) \mu(a \times b) = \mu(a) \times \mu(b) μ(a×b)=μ(a)×μ(b)
  • μ ( a ) ≠ 0 \mu(a) \neq 0 μ(a)=0 μ ( b ) ≠ 0 \mu(b) \neq 0 μ(b)=0,则 μ ( a × b ) = ( − 1 ) k + t = ( − 1 ) k × ( − 1 ) t = μ ( a ) × μ ( b ) \mu(a\times b) = (-1)^{k + t} = (-1)^k \times (-1)^t = \mu(a) \times \mu(b) μ(a×b)=(1)k+t=(1)k×(1)t=μ(a)×μ(b)
  • φ ( x ) \varphi(x) φ(x)是积性函数。

证明在这里插入图片描述

两种莫比乌斯反演的方式的证明(第二种更常用)

前置知识:

在这里插入图片描述

证明:
铅笔佬的证明(也有数论分块的证明)
本人~~(蒟蒻)~~的证明:
在这里插入图片描述

第一种

  • 若有 F ( n ) = ∑ d ∣ n f ( d ) F(n) = \sum_{d|n}{f(d)} F(n)=dnf(d),则: f ( n ) = ∑ d ∣ n μ ( d ) ∗ F ( n d ) f(n) = \sum_{d|n}{\mu(d) * F(\frac{n}{d})} f(n)=dnμ(d)F(dn)
  • 遍历 n n n的所有约数 d d d

证明:
在这里插入图片描述

第二种

  • 若有 ∑ n ∣ d f ( d ) \sum_{n|d}{f(d)} ndf(d),则: f ( n ) = ∑ n ∣ d μ ( d n ) ∗ F ( d ) f(n) = \sum_{n|d}{\mu(\frac{d}{n}) * F(d)} f(n)=ndμ(nd)F(d)
  • 在题目所给数据范围内遍历 n n n的所有倍数 d d d

证明:
在这里插入图片描述

总结:
莫比乌斯反演其实就是一个定理:若有 ∑ d ∣ n f ( d ) \sum_{d|n}{f(d)} dnf(d),则: f ( n ) = ∑ d ∣ n μ ( d ) ∗ F ( n d ) f(n) = \sum_{d|n}{\mu(d) * F(\frac{n}{d})} f(n)=dnμ(d)F(dn)
关键在于:找到一个满足条件的 F ( n ) F(n) F(n) [ F ( n ) F(n) F(n)要好求]和 f ( n ) f(n) f(n) [ f ( n ) f(n) f(n)不好求],通过上述莫比乌斯反演将不好求的 f ( n ) f(n) f(n)用好求的 F ( n ) F(n) F(n)表示。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值