OI群论:从入门到自闭

怎么这么多阅读啊……

这篇文章是群论(其实只有Polya)在信息学奥赛中计数的运用,并不是群论的讲义……


群论可以说是数学中最高深的内容,一个oier去深入了解是不现实的。因此,我们只需要知道结论。

本文主要讲解群论在oi中辅助计数的运用,将尽量做到通俗易懂。

Luogu P4980

题意:给一个长度为 N N N的环,染 N N N种色,旋转同构,求方案数

N ≤ 1 e 9 N \leq 1e9 N1e9

基本概念

置换 一个排列 p p p,表示 i i i可以变成 p i p_i pi

本题中,旋转后得到的排列就是置换。

( 1 , 2 , 3 , . . . , n ) ( 2 , 3 , 4 , . . . , n , 1 ) . . . . . . ( n , 1 , 2 , . . . , n − 1 ) (1,2,3,...,n)(2,3,4,...,n,1)... ...(n,1,2,...,n-1) (1,2,3,...,n)(2,3,4,...,n,1)......(n,1,2,...,n1)都是置换

置换群一堆置换

置换间可以相乘。规则是对每个 i i i依次进行每个置换

本题中,上述 n n n个置换构成置换群

轨道某个数 a a a,经过若干置换(可以为1)回到自己,经过的数在一个轨道上。

人话:环

本题中,若 n = 6 n=6 n=6,对于置换 ( 3 , 4 , 5 , 6 , 1 , 2 ) (3,4,5,6,1,2) (3,4,5,6,1,2), 3 − > 5 − > 1 3->5->1 3>5>1 4 − > 6 − > 2 4->6->2 4>6>2是两个轨道

Burnside引理

本质不同的方案数等于每个置换跑了之后不变化的方案数的平均值

人话:对于每个置换,把每个轨道缩成点,求出当前方案数,所有方案的和除以总置换数就是本质不同的方案数。

这样可以枚举置换,然后暴力跑出置换数,可以做到 O ( n 2 ) O(n^2) O(n2)

然而这题有个特殊性质,容(bu)易(yong)证明

轨道数=gcd(旋转次数,n) \text{轨道数=gcd(旋转次数,n)} 轨道数=gcd(旋转次数,n

这样可以得到公式:

A n s = 1 n ∑ i = 1 n n g c d ( i , n ) Ans=\frac{1}{n}\sum_{i=1}^n n^{gcd(i,n)} Ans=n1i=1nngcd(i,n)

如果我没理解错,这个就是 p o l y a polya polya定理

真心不知道有啥区别

可以做到 O ( n l o g n ) O(nlogn) O(nlogn)

优化

回到

A n s = 1 n ∑ i = 1 n n g c d ( i , n ) Ans=\frac{1}{n}\sum_{i=1}^n n^{gcd(i,n)} Ans=n1i=1nngcd(i,n)

我们发现 g c d ( i , n ) gcd(i,n) gcd(i,n) 只有 O ( n ) O(\sqrt{n}) O(n )种取值

可以枚举 g c d ( i , n ) gcd(i,n) gcd(i,n)

A n s = 1 n ∑ d ∣ n ∑ i = 1 n d [ g c d ( i , n d ) = 1 ] n d Ans=\frac{1}{n}\sum_{d|n}\sum_{i=1}^{\frac{n}{d}}[gcd(i,\frac{n}{d})=1]n^d Ans=n1dni=1dn[gcd(i,dn)=1]nd

不就是欧拉函数吗

A n s = 1 n ∑ d ∣ n ϕ ( n d ) n d = ∑ d ∣ n ϕ ( n d ) n d − 1 Ans=\frac{1}{n}\sum_{d|n}\phi(\frac{n}{d})n^d=\sum_{d|n}\phi(\frac{n}{d})n^{d-1} Ans=n1dnϕ(dn)nd=dnϕ(dn)nd1

然后是暴力枚举 d d d,暴力算 ϕ \phi ϕ,复杂度 O ( n 3 4 ) O(n^{\frac{3}{4}}) O(n43)

并不会证明

#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int MOD=1e9+7;
inline int qpow(int a,int p)
{
	int ans=1;
	while (p)
	{
		if (p&1) ans=(ll)ans*a%MOD;
		a=(ll)a*a%MOD,p>>=1;
	}
	return ans;
}
inline int phi(int x)
{
	int ans=x;
	for (int i=2;i*i<=x;i++)
		if (x%i==0)
		{
			ans/=i,ans*=i-1;
			while (x%i==0) x/=i;
		}
	if (x>1) ans/=x,ans*=x-1;
	return ans;
}
int n;
int calc(const int&d){return (ll)phi(n/d)*qpow(n,d-1)%MOD;}
int main()
{
	int T;
	scanf("%d",&T);
	while (T--)
	{
		int ans=0;
		scanf("%d",&n);
		for (int i=1;i*i<=n;i++)
			if (n%i==0) 
			{
				ans=(ans+calc(i))%MOD;
				if (i*i<n) ans=(ans+calc(n/i))%MOD;
			}
		printf("%d\n",ans);
	}
	return 0;
}

你可能感兴趣的:(OI群论:从入门到自闭)