群论的习题

1. Pólya 定理

传送门
∣ A / G ∣ = 1 ∣ G ∣ ∑ g ∈ G n c ( g ) ∣ A / G ∣ = 1 ∣ G ∣ ∑ i ≤ n ∣ n gcd ⁡ ( i , n ) ∣ ∑ i ≤ n ∣ n gcd ⁡ ( i , n ) ∣ = ∑ i ≤ n ∑ g [ g = gcd ⁡ ( i , n ) ] n g = ∑ g ∣ n n g ∑ i ≤ n [ g = gcd ⁡ ( i , n ) ] = ∑ g ∣ n n g ∑ i ≤ n [ 1 = gcd ⁡ ( i g , n g ) ] = ∑ g ∣ n n g ϕ ( n g ) |A / G| = \frac {1}{|G|} \sum_{g \in G} n^{c (g)} \\ |A / G| = \frac {1}{|G|} \sum_{i \leq n} |n ^ {\gcd (i, n)}| \\ \begin{aligned} &\sum_{i \leq n} |n ^ {\gcd (i, n)}| \\ = &\sum_{i \leq n} \sum_{g} [g = \gcd (i, n)]n^g \\ = &\sum_{g \mid n} n^g\sum_{i \leq n} [g = \gcd (i, n)] \\ = &\sum_{g \mid n} n^g\sum_{i \leq n} [1 = \gcd (\frac {i}{g}, \frac{n}{g})] \\ = &\sum_{g \mid n} n^g \phi (\frac{n}{g}) \end{aligned} A/G=G1gGnc(g)A/G=G1inngcd(i,n)====inngcd(i,n)ing[g=gcd(i,n)]nggnngin[g=gcd(i,n)]gnngin[1=gcd(gi,gn)]gnngϕ(gn)

#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define db double
#define LL long long
// #define int long long
#define PII pair <int, int>
#define ULL unsigned long long
#define MP(x,y) make_pair (x, y)
#define rep(i,j,k) for (int i = (j); i <= (k); i++)
#define per(i,j,k) for (int i = (j); i >= (k); i--)

template <typename T>
void read (T &x) {
    x = 0; T f = 1; 
    char ch = getchar ();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar ();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar ();
    }
    x *= f;
}
template <typename T, typename... Args>
void read (T &x, Args&... Arg) {
    read (x), read (Arg...);
}
const int MaxPrint = 1000;
int Poi_For_Print, Tmp_For_Print[MaxPrint + 5];
template <typename T>
void write (T x) {
	if (x == 0) {
		putchar ('0');
		return;
	}
    bool flag = (x < 0 ? 1 : 0);
    x = (x < 0 ? -x : x);
    while (x) Tmp_For_Print[++Poi_For_Print] = x % 10, x /= 10;
    if (flag) putchar ('-');
    while (Poi_For_Print) putchar (Tmp_For_Print[Poi_For_Print--] + '0');
}
template <typename T, typename... Args>
void write (T x, Args... Arg) {
    write (x); putchar (' '); write (Arg...);
}
template <typename T, typename... Args>
void print (T x, char ch) {
    write (x); putchar (ch);
}
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }

const LL Mod = 1e9 + 7;

int t, n;

unordered_map <int, int> phi;
int get_phi (int x, int lst) {
	int tmp = x;
	if (phi.find (x) != phi.end ()) return phi[x];
	while (x % lst && lst <= x / lst) lst++;
	if (x % lst == 0 && x > 1) {
		int fk = 1;
		while (x % lst == 0)
			x /= lst, fk *= lst;
		return phi[tmp] = get_phi (x, lst + 1) * fk / lst * (lst - 1);
	}
	else {
		if (x > 1) return phi[x] = x - 1;
		else return 1;
	}
	
}
LL quick_pow (LL x, LL y) {
	LL res = 1;
	while (y) {
		if (y & 1) res = (res * x) % Mod;
		x = (x * x) % Mod, y >>= 1;
	}
	return res;
}
LL inv (LL x) {
	return quick_pow (x, Mod - 2);
}

signed main () {
//	freopen ("C:\\Users\\BZ\\Desktop\\.vscode\\1.in", "r", stdin);
//	freopen ("C:\\Users\\BZ\\Desktop\\.vscode\\1.out", "w", stdout);
	
//	rep (i, 1, 100)
//		printf ("phi (%d) = %d\n", i, get_phi (i, 2));
	read (t);
	while (t--) {
		// A / G = \frac {1}{|G|}
		read (n);
		LL res = 0;
		for (int i = 1; i <= n / i; i++)
			if (n % i == 0)
				res = (res + quick_pow (n, i) * get_phi (n / i, 2) + (i != n / i ? quick_pow (n, n / i) * get_phi (i, 2) : 0)) % Mod;
		print (res * inv (n) % Mod, '\n');
	}
    return 0;
}

2.Cards

传送门
首先塞入一个单位元
∣ A / G ∣ = 1 ∣ G ∣ ∑ g ∈ G ∣ g A ∣ = 1 ∣ G ∣ ∑ g ∈ G ∣ g A ∣ g A 即 A 关于 g 的轨道大小 枚举 g , d p 求得 g A \begin{aligned} |A/G| &= \frac{1}{|G|} \sum_{g \in G} |g^{A}| \\ &= \frac{1}{|G|} \sum_{g \in G} |g^{A}| \\ &g^{A} 即 A 关于 g 的轨道大小 \\ &枚举 g,dp 求得 g^A \end{aligned} A/G=G1gGgA=G1gGgAgAA关于g的轨道大小枚举gdp求得gA

#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define db double
#define LL long long
// #define int long long
#define PII pair <int, int>
#define ULL unsigned long long
#define MP(x,y) make_pair (x, y)
#define rep(i,j,k) for (int i = (j); i <= (k); i++)
#define per(i,j,k) for (int i = (j); i >= (k); i--)

template <typename T>
void read (T &x) {
    x = 0; T f = 1; 
    char ch = getchar ();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar ();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar ();
    }
    x *= f;
}
template <typename T, typename... Args>
void read (T &x, Args&... Arg) {
    read (x), read (Arg...);
}
const int MaxPrint = 1000;
int Poi_For_Print, Tmp_For_Print[MaxPrint + 5];
template <typename T>
void write (T x) {
	if (x == 0) {
		putchar ('0');
		return;
	}
    bool flag = (x < 0 ? 1 : 0);
    x = (x < 0 ? -x : x);
    while (x) Tmp_For_Print[++Poi_For_Print] = x % 10, x /= 10;
    if (flag) putchar ('-');
    while (Poi_For_Print) putchar (Tmp_For_Print[Poi_For_Print--] + '0');
}
template <typename T, typename... Args>
void write (T x, Args... Arg) {
    write (x); putchar (' '); write (Arg...);
}
template <typename T, typename... Args>
void print (T x, char ch) {
    write (x); putchar (ch);
}
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }

const int Maxn = 100;
const int Maxs = 20;

int a, b, c, m, p, n;
int x[Maxn + 5];

int quick_pow (int x, int y) {
	int res = 1;
	while (y) {
		if (y & 1) res = (res * x) % p;
		x = (x * x) % p, y >>= 1;
	}
	return res;
}
int inv (int x) {
	return quick_pow (x, p - 2);
}
struct Union_Find_Set {
	int fa[Maxn + 5], _rank[Maxn + 5];
	void MakeSet () {
		rep (i, 1, Maxn)
			fa[i] = i, _rank[i] = 1;
	}
	int FindSet (int x) {
		if (fa[x] != x) fa[x] = FindSet (fa[x]);
		return fa[x];
	}
	void UnionSet (int x, int y) {
		int u = FindSet (x), v = FindSet (y);
		if (u == v) return;
		_rank[v] += _rank[u], fa[u] = v;
	}
}Ufs;
bool vis[Maxn + 5];
int num, sz[Maxn + 5];
int dp[Maxs + 5][Maxs + 5][Maxs + 5];

signed main () {
//	freopen ("C:\\Users\\BZ\\Desktop\\.vscode\\1.in", "r", stdin);
//	freopen ("C:\\Users\\BZ\\Desktop\\.vscode\\1.out", "w", stdout);
	
	read (a, b, c, m, p), n = a + b + c;
	int res = 0;
	rep (step, 1, m + 1) {
		
		num = 0;
		Ufs.MakeSet ();
		
		if (step != m + 1)
			rep (i, 1, n)
				read (x[i]), vis[i] = 0;
		else
			rep (i, 1, n)
				x[i] = i;
		rep (i, 1, n) {
			if (vis[i]) continue;
			int p = i;
			while (!vis[p]) {
				vis[p] = 1;
				Ufs.UnionSet (p, x[p]);
				p = x[p];
			}
		}
		rep (i, 1, n) vis[i] = 0;
		rep (i, 1, n) {
			if (vis[Ufs.FindSet (i)]) continue;
			vis[Ufs.FindSet (i)] = 1;
			sz[++num] = Ufs._rank[Ufs.FindSet (i)];
		}
		rep (i, 0, a)
			rep (j, 0, b)
				rep (k, 0, c)
					dp[i][j][k] = 0;
		dp[0][0][0] = 1;
		rep (i, 1, num) {
			per (j, a, 0)
				per (k, b, 0)
					per(l, c, 0) {
						dp[j][k][l] += (
						(j - sz[i] >= 0 ? dp[j - sz[i]][k][l] : 0)
						+ (k - sz[i] >= 0 ? dp[j][k - sz[i]][l] : 0)
						+ (l - sz[i] >= 0 ? dp[j][k][l - sz[i]] : 0)
						) % p;
						dp[j][k][l] %= p;
					}
//			printf("qwq::%d \n",sz[i]);
		}
		res = (res + dp[a][b][c]) % p;
//		printf ("%d::%d %d\n", step, dp[a][b][c], res);
	}
//	write (dp[a][b][c] % p); putchar ('\n');
	write (res * inv (m + 1) % p);
    return 0;
}

3.有色图

传送门

∣ A / G ∣ = 1 ∣ G ∣ ∑ g ∈ G ∣ A g ∣ |A/G| = \frac{1}{|G|} \sum_{g \in G} |A^{g}| A/G=G1gGAg

a a a 指边组成的群,这个量很大,所以我们考虑枚举点组成的群,对于同个点轮换之间的边,边轮换长度为点轮换长度的一半(向下取整),不同点轮换之间,边轮换长度为两个点轮换长度 ( i   & j i \ \& j i &j) 的最小公倍数,则个数为 i ∗ j l c m ( i , j ) = g c d ( i , j ) \frac{i * j}{lcm (i, j)} = gcd (i, j) lcm(i,j)ij=gcd(i,j)

对于点轮换长度组成的序列 B B B,边轮换个数为

( ∑ i = 1 n u m ⌊ b i 2 ⌋ ) + ( ∑ i = 1 n u m ∑ j = i + 1 n u m g c d ( b i , b j ) ) (\sum_{i = 1}^{num} \lfloor \frac{b_i}{2} \rfloor) + (\sum_{i = 1}^{num} \sum_{j = i + 1}^{num} gcd (b_i, b_j)) (i=1num2bi⌋)+(i=1numj=i+1numgcd(bi,bj))

考虑每个点属于哪个点群

p r e i = ∑ j = 1 i b j ∑ i ( n − p r e i − 1 p r e i − p r e i − 1 ) = n ! ∏ i b i ! \begin{aligned} &pre_i = \sum_{j = 1}^{i} b_j \\ &\sum_{i} \binom{n - pre_{i - 1}}{pre_i - pre_{i - 1}} \\ = &\frac{n!}{\prod_i b_i!} \end{aligned} =prei=j=1ibji(preiprei1nprei1)ibi!n!

内部有圆排列,考虑断环成链,然后由于钦定断点,而断点与答案无关,需要消序。

b i ! b i = ( b i − 1 ) ! \frac{b_i!}{b_i} = (b_i-1)! bibi!=(bi1)!

还要考虑去重,轮换长度相同的点轮换可以交换,对于点轮换长度相同的轮换个数组成的序列 C C C

答案即为

( ∏ i ( b i − 1 ) ! ) 1 ∣ G ∣ n ! ∏ b i ! 1 ∏ c i ! m ( ∑ i = 1 n u m ⌊ b i 2 ⌋ ) + ( ∑ i = 1 n u m ∑ j = i + 1 n u m g c d ( b i , b j ) ) 1 ∏ i b i 1 ∏ i c i ! m ( ∑ i = 1 n u m ⌊ b i 2 ⌋ ) + ( ∑ i = 1 n u m ∑ j = i + 1 n u m g c d ( b i , b j ) ) \begin{aligned} (\prod_i (b_i - 1)!) \frac{1}{|G|} \frac{n!}{\prod b_i!} \frac{1}{\prod c_i!} m^{(\sum_{i = 1}^{num} \lfloor \frac{b_i}{2} \rfloor) + (\sum_{i = 1}^{num} \sum_{j = i + 1}^{num} gcd (b_i, b_j))} \\ \frac{1}{\prod_i b_i} \frac{1}{\prod_i c_i!} m^{(\sum_{i = 1}^{num} \lfloor \frac{b_i}{2} \rfloor) + (\sum_{i = 1}^{num} \sum_{j = i + 1}^{num} gcd (b_i, b_j))} \end{aligned} (i(bi1)!)G1bi!n!ci!1m(i=1num2bi⌋)+(i=1numj=i+1numgcd(bi,bj))ibi1ici!1m(i=1num2bi⌋)+(i=1numj=i+1numgcd(bi,bj))


4.忘了

传送门

题意:长度为 n n n 的环,给这个环染色( m m m 种颜色),不允许相邻两个位置染同色,问方案数(通过旋转可变为一样的染色方式算一种)

∣ A / G ∣ = ∑ g ∈ G ∣ A g ∣ |A/G| = \sum_{g \in G} |A^g| A/G=gGAg

旋转了 i i i 位,轮换个数为 gcd ⁡ ( i , n ) \gcd (i, n) gcd(i,n)

可以将每个轮换抽象为一个点,再连起来,容易知道这是等价的,环的长度为 gcd ⁡ ( i , n ) \gcd (i, n) gcd(i,n)

f ( x ) f(x) f(x) 表示长度为 x x x 的环染色方案数。

∣ A / G ∣ = ∑ g ∈ G ∣ A g ∣ = ∑ i = 1 n f ( gcd ⁡ ( i , n ) ) = ∑ _ g c d = 1 n f ( _ g c d ) ∑ i = 1 n 1 [ g c d ( i , n ) = _ g c d ] = ∑ _ g B c d = 1 f ( _ g c d ) ϕ ( n _ g c d ) [ _ g c d ∣ n ] \begin{aligned} |A/G| &= \sum_{g \in G} |A^g| \\ &= \sum_{i = 1}^{n} f (\gcd (i, n)) \\ &= \sum_{\_gcd = 1}^n f(\_gcd) \sum_{i = 1}^n 1[gcd (i, n) = \_gcd] \\ &= \sum_{\_gBcd = 1} f (\_gcd) \phi (\frac{n}{\_gcd})[\_gcd | n] \end{aligned} A/G=gGAg=i=1nf(gcd(i,n))=_gcd=1nf(_gcd)i=1n1[gcd(i,n)=_gcd]=_gBcd=1f(_gcd)ϕ(_gcdn)[_gcdn]

{ f ( 0 , 0 , n ) = f ( 0 , 1 , n − 1 ) + f ( 0 , 0 , n − 1 ) f ( 0 , 1 , n ) = f ( 1 , 0 , n − 1 ) ∗ m + f ( 0 , 0 , n − 1 ) ∗ m f ( 1 , 0 , n ) = f ( 1 , 1 , n − 1 ) + f ( 1 , 0 , n − 1 ) f ( 1 , 1 , n ) = f ( 1 , 0 , n − 1 ) ∗ m \begin{cases} f (0, 0, n) = f (0, 1, n - 1) + f (0, 0, n - 1) \\ f (0, 1, n) = f (1, 0, n - 1) * m + f (0, 0, n - 1) * m \\ f (1, 0, n) = f (1, 1, n - 1) + f (1, 0, n - 1) \\ f (1, 1, n) = f (1, 0, n - 1) * m \end{cases} f(0,0,n)=f(0,1,n1)+f(0,0,n1)f(0,1,n)=f(1,0,n1)m+f(0,0,n1)mf(1,0,n)=f(1,1,n1)+f(1,0,n1)f(1,1,n)=f(1,0,n1)m

f ( i ) = ( f ( 0 , 0 , i ) + f ( 1 , 0 , i ) + f ( 0 , 1 , i ) ) n f (i) = \frac{(f (0, 0, i) + f (1, 0, i) + f (0, 1, i))}{n} f(i)=n(f(0,0,i)+f(1,0,i)+f(0,1,i))

矩阵加速求 f f f 即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值