Yukiの群论笔记

Preface

被数学折磨中...
$\ $

  • 群的定义

给定一个集合 \(G\),以及一个二元运算 \(\cdot\),若满足如下的性质,则称 \((G,\cdot)\) 为一个群:

\(1.\) 封闭性:对于任意 \(a,b\in G\),都有 \(a\cdot b\in G\).
\(2.\) 结合律:对于任意 \(a,b,c\in G\),都有 \(a\cdot(b\cdot c)=a\cdot b\cdot c\).
\(3.\) 单位元:存在唯一的 \(e\in G\),对任意的 \(a\in G\) 都有 \(e\cdot a=a\cdot e=a\).
\(4.\) 逆元:对任意 \(a\in G\),有且仅有一个与之对应的 \(a^{-1}\in G\) 使得 \(a\cdot a^{-1}=a^{-1}\cdot a=e\).

举个例子,考虑模 \(n\) 的完全剩余系,其在模 \(n\) 加法下构成群,记作 \(\mathbb{Z}_n\).

在不混淆的情况下,可以将 \(a\cdot b\) 简写为 \(ab\).

若只满足 \(1,2\),则称 \((G,\cdot)\)半群;若只满足 \(1,2,3\),则称 \((G,\cdot)\)幺半群

若对于一个群 \((G,\cdot)\),对任意 \(a,b\in G\) 都有 \(ab=ba\),则称 \((G,\cdot)\)阿贝尔群

我们称群的\(G\) 的大小,即 \(|G|\)

\(G\) 为有限集(即 \(|G|\neq\infty\)),则称 \((G,\cdot)\)有限群,否则成为无限群

给定群 \((G,\cdot)\)\((H,*)\),在集合 \(G\times H\) 上定义运算:对于任意 \((g_i,h_i)\in G\times H\),有 \((g_1,h_1)\circ (g_2,h_2)=(g_1\cdot g_2,h_1\times h_2)\),则 \(G\times H\)\(\circ\) 运算下构成一个群,称为 \(G\)\(H\)直积群.

设集合 \(X\) 上有一个双射:\(X\rightarrow X\),集合 \(X\) 上所有的置换构成一个群,称为对称群,记作 \(Sym\ X\).
特别地,当 \(X=\{1,2,...,n\}\) 时,记其对称群为 \(S_x\).

下面是一些结论:

\(1.\) 对于 \(a,b,c\in G\),若 \(ab=ac\),则 \(b=c\).

证明:

\(b=eb=a^{-1}ab=a^{-1}ac=ec=c\).

\(2.\) 定义 \(a\in G\)\(n\) 次幂为 \(aaa...aa\ (\)\(n\)\(a)\),则 \(a^{m+n}=a^ma^n,a^{mn}=(a^m)^n\).

证明是显然的,只需将式子展开即可.

  • 子群与 Lagrange 定理

子群的定义:

\((G,\cdot)\) 是一个群,\(H\)\(G\) 的子集且 \(H\) 也是一个群,则称 \(H\)\(G\)子群,记作 \(H\leq G\)
特别地,若 \(H\)\(G\) 的真子集,则称 \(H\)\(G\)真子群,记作 \(H<G\).

子群判别定理:

\(G\) 为一个群,\(H\)\(G\) 的非空子集,则 \(H\)\(G\) 的子群当且仅当对于任意 \(a,b\in H\),都有 \(ab^{-1}\in H\).

证明:

因为 \(G\) 为群,所以 \(H\) 存在结合律;
任取 \(a\),有 \(aa^{-1}=e\in H\),所以存在单位元;
因为 \(ea^{-1}=a^{-1}\in H\),所以对于任意 \(a\in H\),都存在 \(a^{-1}\)
因为 \(a(b^{-1})^{-1}=ab\in H\),所以 \(H\) 满足封闭律;

陪集的定义:

对于子群 \(H\leq G\) 和任意 \(a\in G\),记 \(aH=\{ah\mid h\in H\}\)\(Ha=\{ha\mid h\in H\}\).
我们称 \(aH\)\(H\)左陪集,而 \(Ha\)\(H\)右陪集.

Lagrange 定理:

\(H\) 为有限群 \(G\) 的子群,则 \(|H|\) 整除 \(|G|\),即 \(|H|\mid |G|\).
也可以说 \(H\) 的所有不同左陪集(右陪集)将 \(G\) 划分成多个大小一样的部分.

证明:

对于任意的 \(a\in G\),一定有 \(a=ae\in aH\),所以 \(H\) 的所有左陪集可覆盖 \(G\).
接下来证明任意两个不同的左陪集没有相交的部分.
假设 \(aH\neq bH\),但存在 \(h_1,h_2\in H\) 使得 \(ah_1=bh_2\). 所以 \(a=b(h_2h_1^{-1})\).
所以 \(aH=\{ah\mid h\in H\}=\{b(h_2h_1^{-1}h)\mid h\in H\}\),故 \(aH\subseteq bH\),同理可得 \(bH\subseteq aH\),故 \(aH=bH\),矛盾. 故该命题成立.

  • 群作用

群作用的定义:

对于群 \(G\) 和集合 \(X\),若有映射 \(\alpha\) 接受一个 \(G\) 中元素和一个 \(X\) 中元素,返回一个 \(X\) 中元素,且满足:
\(~~~~1\). \(\alpha(e,x)=x\) 对任意 \(x\in X\) 都成立,其中 \(e\) 为单位元.
\(~~~~2\). \(\alpha(g,\alpha(h,x))=\alpha(gh,x)\) 对任意 \(g,h\in G,x\in X\) 都成立.
则称 \(G\) 作用 \(H\). 不引起歧义时,可简记 \(\alpha(g,x)\)\(gx\).

看上去非常晕. 这里举个例子.

Farmer John\(5\) 头奶牛,编号为 \(1,2,3,4,5\),顺序排成一列. 有直积群 \(G=\mathbb{Z}_2\times\mathbb{Z}_3\),取 \((a,b)\in G\),向这些奶牛下达命令:前 \(2\) 头轮换 \(a\) 次,后 \(3\) 头轮换 \(b\) 次. 如下达 \((1,1)\) 这个命令,奶牛们就会重排为 \(2,1,4,5,3\). 这时,我们可以称 \(G\) “作用” 于这些奶牛.

对于这样的群作用,我们可以对任意 \(g\) 构造 \(X\rightarrow X\) 的映射 \(\psi_g\).

这里有一些结论:

\(1.\) 对于任意的 \(g,h\in G\),有 \(\psi_g\circ\psi_h=\psi_{gh}\).

证明:\((\psi_g\circ\psi_h)(x)=\psi_g(\psi_h(x))=g(hx)=ghx=\psi_{gh}x\).

\(2.\ \psi_g\) 一定为 \(Sym\ X\) 中的元素.

证明:对于任意的 \(x\in X\),有 \(x=ex=gg^{-1}x=\psi_g(g^{-1}x)\),故 \(\psi_g\) 为满射,从而是双射.

轨道、稳定化子和不动点的定义:

任取元素 \(x\in X\),定义 \(x\) 所在的轨道 \(Gx=\{gx\mid g\in G\}\)
定义 \(x\) 的稳定化子 \(G_x=\{g\in G\mid gx=x\}\)
任取元素 \(g\in G\),定义 \(g\) 的不动点为 \(X^g=\{x\in X\mid gx=x\}\)

轨道划分:

所有不同的轨道将 \(X\) 划分为了多个部分,记分成的部分个数 \([X:G]\).

证明:

与 Lagrange 定理的证明类似.
显然所有的轨道覆盖了 \(G\).
\(Gx\neq Gy\) 且它们有相交部分,设 \(ax=by=z\),则 \(Gx=\{gx\mid g\in G\}=\{(ga^{-1}b)y\mid g\in G\}\),故 \(Gx\subseteq Gy\),同理 \(Gy\subseteq Gx\),于是 \(Gx=Gy\),矛盾.

轨道-稳定子定理:

对于任意元素 \(x\in X\)\(G_x\) 都是 \(G\) 的子群,且 \(|Gx||G_x|=|G|\).

证明:

因为 \((ab^{-1})x=(ab^{-1}b)x=ax=a\),根据子群判定定理,\(G_x\)\(G\) 子群.
根据 Lagrange 定理,\(G_x\) 的不同左陪集可将 \(G\) 分为 \(|G|/|G_x|\) 个部分.
\(k=|G|/|G_x|\),我们从每个部分中都取出一个元素,可取出 \(g_1,g_2,...,g_k\) 这些元素. 接下来证明这些元素和轨道中的元素具有一一对应的关系.

先证明当 \(g_i\neq g_j\) 时,\(g_ix \neq g_jx\). 假设结论不成立,则 \(g_i^{-1}g_jx=x\),故 \(g_i^{-1}g_j\in G_x\).
所以 \(g_j=g_i(g_i^{-1}g_j)\),所以 \(g_j\in g_iG_x\),矛盾.

再证明对于任意 \(y\in G_x\),存在 \(g_ix=y\),因为 \(y\)\(G_x\) 中的元素,则可以设 \(y=gx\).
\(g_i\)\(gG_x\) 这个部分,则存在 \(h\) 使得 \(g_i=gh\),于是有 \(ghx=g_ix=y\).

能证明是一一对应的,则元素相等,证毕.

  • Burnside 引理和 Pólya 定理

Burnside 引理:

\(G\) 作用于 \(X\),则轨道条数等于不动点个数的平均值,即:

\[[X:G]=\frac{1}{|G|}\sum\limits_{g\in G}|X^g| \]

证明:

\([X:G]=\sum\limits_{i=1}^k1=\sum\limits_{i=1}^k\sum\limits_{x\in G_{x_i}}\frac{1}{|G_{x_i}|}=\sum\limits_{i=1}^k\sum\limits_{x\in Gx_i}\frac{1}{|Gx|}\)
根据轨道划分定理,有 \(\sum\limits_{i=1}^k\sum\limits_{x\in G_{x_i}}=\sum\limits_{x\in X}\)
因此 \([X:G]=\sum\limits_{x\in X}\frac{1}{|Gx|}=\sum\limits_{x\in X}\frac{|G_x|}{|Gx||G_x|}=\frac{1}{|G|}\sum\limits_{x\in X}|G_x|\)
这个式子等价于 \(\frac{1}{|G|}\sum\limits_{g\in G}|X^g|\).

Pólya 定理:

在解决染色问题的时候,我们一般需要求出不动点的数量.

对于一个置换,通过置换向能达到的元素连一条边,就会发现形成了若干个环.

假设对置换 \(g\),设 \(c(g)\) 为置换的循环数,共有 \(m\) 中颜色,那么 Burnside 引理也可改写成:

\[[X:G]=\frac{1}{|G|}\sum\limits_{g\in G}m^{c(g)} \]

这就是 Pólya 定理.

  • 双半群模型

带区间修改和区间查询的线段树,一般会有信息的合并,发现这些信息构成一个集合,赋予一个运算 \(+\),记作 \((D,+)\).

其符合性质:

\(~~~~1.D+D\rightarrow D\).
\(~~~~2.\forall a,b,c\in D\),有 \(a+(b+c)=(a+b)+c\).

但是这些信息不一定具有交换律. 则这些信息及其运算构成一个半群.

修改时我们会打上 \(\texttt{lazytag}\),这些标记我们也扔到一个集合里,赋予一个运算 \(\times\),记作 \((T,\times)\).

其符合性质:

\(~~~~1.T+T\rightarrow T\).
\(~~~~2.\forall a,b,c\in T\),有 \(a+(b+c)=(a+b)+c\).
\(~~~~3.\) 具有空标记 \(e\) 满足 \(\forall a\in T,ae=ea=a\).

这些标记及其运算构成一个幺半群.

而标记和信息间有如下性质:

\(~~~~1.T+D\rightarrow D\),即标记和信息合并后仍是信息.
\(~~~~2.\forall a\in D,b,c\in T\),有 \(a\times(b\times c)=(a\times b)\times c\). 即先合并两个标记与先合并标记与信息结果不变.
\(~~~~3.\forall a,b\in D,c\in T\),有 \((a+b)\times c=a\times c+b\times c\). 即 \(\times\)\(+\) 满足分配律.

若两个群满足上述条件,则称为双半群结构. 若问题满足上述要求,则称为双半群模型.

具体实践将在习题部分讲解.

\(1.\) P4980 【模板】Polya 定理

这一题的作用很简单,就是旋转,\(G=\{\)旋转 \(0\) 次,旋转 \(1\) 次,旋转 \(2\) 次,...,旋转 \(n-1\)\(\}\).

对于旋转 \(k\) 次的不动点数,我们发现最小循环节为 \(g=\gcd(k,n)\),所以前 \(g\) 个都可以任意涂色,则不动点数为 \(n^{\gcd(k,n)}\).

于是题目就变成求 \(\frac{1}{n}\sum\limits_{k=1}^nn^{\gcd(k,n)}\),可以转换成求 \(\frac{1}{n}\sum\limits_{k\mid n}n^k\varphi(\frac{n}{k})\).

代码如下:


#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007
#define I inline
ll n,t,ans;
I ll qpow(ll a,ll x){
    ll ret=1,base=a;
    while(x){
        if(x&1)ret=ret*base%mod;
        base=base*base%mod,x>>=1;
    }
    return ret;
}
I ll euler(ll x){
    ll ret=1,num=x;
    for(ll i=2;i*i<=x;i++){
        if(x%i)continue;
        x/=i,ret=ret*(i-1);
        while(x%i==0)ret=ret*i,x/=i;
    }
    if(x!=1)ret=ret*(x-1);
    return ret;
}
I void solve(){
    cin>>n,ans=0;
    for(ll i=1;i*i<=n;i++){
        if(n%i)continue;
        ans=(ans+qpow(n,i)*euler(n/i)%mod)%mod;
        if(i*i==n)continue;
        ans=(ans+qpow(n,n/i)*euler(i)%mod)%mod;
    }
    cout<<ans*qpow(n,mod-2)%mod<<'\n';
}
int main(){
    ios::sync_with_stdio(0);
    cin>>t;while(t--)solve();
    return 0;
}

\(2.\) P4727 [HNOI2009] 图的同构计数

对于这个题,集合 \(X\) 即不同的图(只需标号不同即可),而 \(G\) 则为所有的标号方式,而“颜色”只有两种,存在和不存在.

现在题目就变成了在一个完全图上染色,求本质不同的图的个数.

对于一个点置换,我们怎么求出其不动点数量呢?

首先,我们发现位于同一个等价类的边,要么都染,要么不染,不然就会不一样.
所以若该置换下有 \(k\) 个等价类,则不动点数为 \(2^k\) 个. 然后就转化为求一个置换下有多少个等价类.

一个置换可以拆成多个环,如 \(g=(4\ 3\ 2\ 1)\) 就可以拆成 \((4\ 1)\circ(3\ 2)\).
对于在同一个环上的边,手推可得其等价类个数为 \(\lfloor\frac{x}{2}\rfloor\) 个,其中 \(x\) 为环的元素数.
那连接不同环的边,其等价类数又是多少呢?
假设两个环的元素数分别为 \(g_1,g_2\),则连的边数为 \(g_1g_2\).
而每一条边经过 \(\rm{lcm}(g_1,g_2)\) 次置换后回到原位,所以每个等价类大小为 \(\rm{lcm}(g_1,g_2)\),共有 \(\frac{g_1g_2}{\rm{lcm}(g_1,g_2)}=\gcd(g_1,g_2)\) 个等价类.

对于每一种置换,设有 \(k\) 个环,每个环大小为 \(g_i\),等价类个数就是 \(\sum\limits_{i=1}^k(\lfloor\frac{g_i}{2}\rfloor+\sum\limits_{j=1}^{i-1}\gcd(g_i,g_j))\).

现在我们能求出每一种置换的不动点数,但置换数有 \(n!\) 个,如果一个个枚举还是会超时.
我们发现有如果两个置换的环的数量相等,且每个环内元素对应相等,则这两个置换的不动点数是相等的.
所以我们可以枚举 \(n\) 的拆分来减小枚举量.

\(n\) 的一个拆分 \(g\) 对应多少个置换呢?首先我们随便取,一共是 \(n!\) 种.
环内部是一个圆排列,所以要除以 \(\prod g_i\) (先除以 \(\prod (g_i!)\) 再乘 \(\prod (g_i-1)!\)),其中 \(g_i\) 为每个环的大小.
同时,对于大小相等的环,怎么排列都是可以的,所以还要除以 \(\prod (s_i!)\),其中 \(s_i\) 为某个大小的环的个数.

最终的式形如这样:

\[[X/G]=\frac{1}{|G|}\sum\limits_g2^p\frac{n!}{\prod (g_i)\prod (s_i!)} \]

\[=\sum\limits_g\frac{2^p}{\prod (g_i)\prod (s_i!)}, \]

\[p=\sum\limits_{i=1}^k(\lfloor\frac{g_i}{2}\rfloor+\sum\limits_{j=1}^{i-1}\gcd(g_i,g_j)) \]

枚举计算即可,代码如下:


#include<bits/stdc++.h>
using namespace std;
#define mod 997
#define mxn 110
#define ll long long
#define I inline
ll n,ans,g[mxn],poww[mxn];
I void init(){
    poww[0]=1;
    for(ll i=1;i<=100;i++)poww[i]=poww[i-1]*i%mod;
}
I ll qpow(ll a,ll x){
    ll ret=1,base=a;
    while(x){
        if(x&1)ret=ret*base%mod;
        base=base*base%mod,x>>=1;
    }
    return ret;
}
I void solve(ll cnt){
    ll p=0,sum=1;
    for(ll i=1;i<=cnt;i++){
        p+=g[i]/2,sum=sum*g[i]%mod;
        for(ll j=1;j<i;j++)p+=__gcd(g[i],g[j]);
    }
    for(ll i=1;i<=cnt;i++){
        ll j=i;
        while(j<=cnt&&g[j]==g[i])j++;
        sum=sum*poww[j-i]%mod,i=j-1;
    }
    ans=(ans+qpow(2,p)*qpow(sum,mod-2)%mod)%mod;
}
I void dfs(ll cnt,ll lst,ll res){
    if(!res){solve(cnt-1);return;}
    for(ll i=lst;i<=res;i++){
        g[cnt]=i;
        dfs(cnt+1,i,res-i);
    }
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n,init();
    dfs(1,1,n),cout<<ans;
    return 0;
}

还有一题 P4128 [SHOI2006] 有色图,和上题是一样的,就是颜色数量改了一下,代码就不放了.

\(3.\) P1446 [HNOI2008] Cards

对于每一个置换,先算出其循环数和大小,再写一个三维背包(也可以变成二维)计算每个循环染色的方法数.


#include<bits/stdc++.h>
using namespace std;
#define mxn 110
#define ll long long
#define I inline
ll Sr,Sb,Sg,m,mod,n,ans,tmp;
ll g[mxn],vis[mxn],cnt,sum,h[mxn];
ll dp[mxn][mxn];
I ll qpow(ll a,ll x){
    ll ret=1,base=a;
    while(x){
        if(x&1)ret=ret*base%mod;
        base=base*base%mod,x>>=1;
    }
    return ret;
}
I void init(){
    for(int i=1;i<=n;i++)vis[i]=0;
    for(int i=1;i<=cnt;i++)h[i]=0;
    memset(dp,0,sizeof(dp)),dp[0][0]=1;
    cnt=0;
}
I void solve(){
    for(int i=1;i<=n;i++){
        if(vis[i])continue;
        int j=g[i];vis[i]=1,sum=1;
        while(!vis[j])sum++,vis[j]=1,j=g[j];
        h[++cnt]=sum;
    }
    for(int i=1;i<=cnt;i++){
        for(int j=Sr;j>=0;j--)
            for(int k=Sb;k>=0;k--){
                if(j>=h[i])dp[j][k]=(dp[j-h[i]][k]+dp[j][k])%mod;
                if(k>=h[i])dp[j][k]=(dp[j][k-h[i]]+dp[j][k])%mod;
            }    
    }
    ans=(ans+dp[Sr][Sb])%mod;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>Sr>>Sb>>Sg>>m>>mod,n=Sr+Sb+Sg,tmp=m;
    while(m--){init();for(int i=1;i<=n;i++)cin>>g[i];solve();}
    init();for(int i=1;i<=n;i++)g[i]=i;solve();
    cout<<ans*qpow(tmp+1,mod-2)%mod;
    return 0;
}

\(4.\) P2561 [AHOI2002] 黑白瓷砖

先计算置换数:不动,旋转和对称,组合起来是 \(6\) 种.

瓷砖数量为 \(n=\frac{m(m+1)}{2}\) 种,则单位元的不动点数为 \(2^n\) 种.

旋转的不动点数为 \(2\times2^{\lceil\frac{n}{3}\rceil}\) 种.

对称的不动点数为 \(3\times2^{\frac{n-\lceil\frac{m}{2}\rceil}{2}+\lceil\frac{m}{2}\rceil}\) 种.

加起来除以 \(6\) 即可.


n=int(input())
m=n
n=n*(n+1)//2
ans=(2**n+2*(2**((n+2)//3))+3*(2**((n-(m+1)//2)//2+(m+1)//2)))//6
print(ans)

\(5.\) P8868 [NOIP2022] 比赛

双半群模型的具体应用.

首先发现这题需要扫描线,我们维护数组 \(s\),当右移到 \(r\) 的时候,给 \(s_l(1\leq l\leq r)\) 加上 \(\max\limits_{i \in[l,r]}A_i\max\limits_{i \in[l, r]}B_i\),最后区间查询 \([q_l,q_r]\) 就行了.

但是 \(\max\limits_{i \in[l, r]}A_i\)\(\max\limits_{i \in[l, r]}B_i\) 很鬼畜,考虑把它们也拎出来作为数组 \(a,b\)\(r\) 向右移时就相当于后缀的区间覆盖,这里可以用单调栈求解.

接下来构造信息和标记. 但是我还不会,所以先咕着.

这里给出我的参考资料:

题解 LGP8868【[NOIP2022] 比赛】/【模板】“历史版本和”线段树
sol of P8868
数据结构闲谈:范围分治的「双半群」模型
浅谈双半群模型

posted @ 2025-01-12 20:21  nagato__yuki  阅读(51)  评论(0)    收藏  举报