前言
终于学会了
我好菜啊
问题
比如给出一个环,环上有n个点,每个点可以染一种颜色,共m种不同的颜色,求在循环同构下的不同方案数
不会burnside的话连暴力都不好写
burnside
一些定义
置换:指一次或多次操作之和,类似矩乘中的转移矩阵
不定点:若一种方案在某个置换下等于原方案,则称这种置换是这个方案的不定点
如图是n=4,m=2的情况,可以发现一共有16种染色情况和4种置换(就是n种)
但仔细观察发现本质只有(1)(2)(3,4,5,6)(7,8,9,10)(11,12)(13,14,15,16)(括号内为本质相同的一种)共6种情况
如何快速计算不同方案?
考虑把本质相同的几种情况归为一种,即对答案贡献为1
首先设一类置换的循环节长度为c,则循环节个数为n/c,本质相同的一共有c种(在一种的基础上左右旋转),每一种的不定点个数为n/c(把循环节轮换,共n/c个)
因为c并不好求,所以考虑直接算出答案
可以发现本质相同个数*不定点个数=n,对最终答案/n就是总方案
由于每种置换都算了所有情况的不定点,所以对于c种本质相同的方案都会算一次不定点,因此不同方案l等于
l
=
∑
C
(
a
i
)
n
l=\frac{\sum{C(ai)}}{n}
l=n∑C(ai)(C(i)表示方案i的不定点个数)
对于一般情况:
,其中G为置换集
polya
然而。。。
如果要计算不定点C(ai)的话,那就要枚举n^m种情况并计算不动点
但这样还不如暴力
所以就需要polya定理来提供具体的计算方式
对于一种置换可以被分成若干个循环节(即从一个位置出发走一圈走回权威,循环节之间相邻),如果要为不定点则每个循环节内点的颜色都要各自相同
所以第i种置换设有bi个循环节
l
=
∑
m
b
i
n
l=\frac{\sum{m^{bi}}}{n}
l=n∑mbi
而在这个问题中,bi=gcd(n,i)
证明考虑n和i互质时,则置换一定可以选择完1~n中的所有数,故为1
如果把n和i同时扩大,则bi一定会扩大同样的倍数
感性理解
如上面那个问题,bi分别等于4(初始状态)、1、2、1,则方案l=(24+21+22+21)/4=6
例题
jzoj4800. 【GDOI2017模拟9.24】周末晚会
Description
Irena和Sirup正准备下个周末的Party。为这个Party,他们刚刚买了一个非常大的圆桌。他们想邀请每个人,但他们现在不知道如何分配座次。Irena说当有超过K个女孩座位相邻(即这些女孩的座位是连续的,中间没有男孩)的话,她们就会说一整晚的话而不和其他人聊天。
Sirup没有其他选择,只有同意她。然而,作为一名数学家,他很快地痴迷于所有可能方案。
题目说明:
N个人围绕着圆桌坐着,其中一些是男孩,另一些是女孩。你的任务是找出所有合法的方案数,使得不超过K个女孩座位是连续的。
循环同构会被认为是同一种方案。
Input
第一行有一个数T,表示以下有T组数据,每组数据有两个整数N,K。
每组数据之间有一个空行隔开。
Output
输出T行,每行顺次对应一组测试数据。
每组数据你需要输出最后的方案数除以100000007的余数。
Sample Input
3
3 1
3 3
4 1
Sample Output
2
4
3
解释:
第一组数据的方案是:MMM,MMW (M是男孩, W是女孩)。
第二组数据的方案是:MMM,MMW,MWW,WWW。
第三组数据的方案是:MMMM, MMMW,MWMW。
Data Constraint
对于20%的数据T<=20;
对于100%的数据T<=50;
对于20%的数据N,K<=20;
对于100%的数据N,K<=2000;
题解
如果没有k的限制,那就可以直接套式子
但加上k的限制就不能直接用了,因为可能有>k个循环节坐了女生
可以发现,如果每个循环节第一个位置组成的序列是合法的,那么剩下的也都会合法
所以只需要考虑前(n,i)个
设f[i]表示长度为i且首位坐男生,而且包含所有男生的合法方案
转移就枚举倒数第二个男生,注意中间的女生不能超过k
处理完f就好搞了,考虑还剩下多少个女生(同样不能超过k),贡献就是f[循环节个数-剩下女生个数]*(剩下女生个数+1)(因为可以旋转)
当然还可以用前缀和优化然而貌似不用也可以过
其它题解的传送门:
https://www.cnblogs.com/DUXT/p/5958205.html
https://blog.youkuaiyun.com/WerKeyTom_FTD/article/details/52651361
code
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define mod 100000007
#define Mod 100000005
#define N 2000
using namespace std;
long long f[N+1];
int T,n,i,j,k;
long long s,ans;
long long qpower(long long a,int b)
{
long long ans=1;
while (b)
{
if (b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void init()
{
f[1]=1;
f[2]=1;
fo(i,3,n)
{
f[i]=0;
fo(j,max(i-k-1,1),i-1)
f[i]=(f[i]+f[j])%mod;
}
}
int gcd(int n,int m)
{
int r=n%m;
while (r)
{
n=m;
m=r;
r=n%m;
}
return m;
}
int main()
{
for (scanf("%d",&T); T; --T)
{
scanf("%d%d",&n,&k);
ans=0;
if (n<=k)
{
fo(i,1,n)
ans=(ans+qpower(2,gcd(n,i)))%mod;
}
else
{
init();
fo(i,1,n)
{
s=gcd(n,i);
fo(j,max(s-k,1),s)
ans=(ans+f[j]*(s-j+1))%mod;
}
}
printf("%lld\n",ans*qpower(n,Mod)%mod);
}
}
参考资料
https://blog.youkuaiyun.com/liangzhaoyang1/article/details/72639208
https://www.cnblogs.com/beisong/p/4767858.html