【题解】UVA - 11255(Burside)

【题解】UVA - 11255 (Burside)

OI生涯第一道Burside?

上次伦的火箭课件已经进行了扫盲,具体来说,定理内容是这样的:

从我浅薄的知识来看,Polya只是Burside的计数版本

Burside

设置换群\(G\),以及一个可以被这个群作用的集合\(S\),那么\(G_S\)的轨道数量(本质不同的\(S\)中的元素)是:

\[\sum_{g\in G} {|\text{stab }S_g|\over |G|} \]

证明被我吃了

  • 旋转同构

    • 考虑顺时针转\(k\in[1,n]\)步,对于旋转\(k\)步,总共有\(\gcd (k,n)\)种不同的"循环"需要填,这些循环必须满足循环内所有元素相同(这样才能保持旋转时不会造成不同)。每个循环的长度是\(n\over \gcd(k,n)\),直接算即可。
  • 翻转同构(len=2)

    • 加旋转的翻转,意义是有\(n\)种对称轴,同样地计算一下就行了。

      • 奇数

        枚举翻转的那个颜色,再进行翻转。

      • 偶数

        • 对称轴经过两个点

          • 枚举两个点的颜色即可
        • 对称轴经过一个空隙

        • 直接算就好了

关键是恰当地对置换进行分类

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;  typedef long long ll;
const int maxn=40+5;
ll c[maxn][maxn];
void pre(const int&n){
	for(int t=0;t<=n;++t)
		for(int i=c[t][0]=1;i<=t;++i)
			c[t][i]=c[t-1][i-1]+c[t-1][i];
}
int a[3],b[3],n;

ll Polya(int k){
	int s=0;
	for(int t=0;t<3;++t)
		if(b[t]%k||b[t]<0) return 0;
		else b[t]/=k,s+=b[t];
	ll ret=1;
	for(int t=0;t<3;++t)
		ret*=c[s][b[t]],s-=b[t];
	return ret;
}

int main(){
	pre(41);
	int T;
	cin>>T;
	size_t siz=sizeof a;
	while(T--){
		n=0;
		for(int t=0;t<3;++t) cin>>a[t],n+=a[t];
		ll ans=0;
		for(int t=1;t<=n;++t)
			memcpy(b,a,siz),ans+=Polya(n/__gcd(t,n));
		if(n&1)
			for(int t=0;t<3;++t)
				memcpy(b,a,siz),--b[t],ans+=Polya(2)*n;
		else{
			for(int t=0;t<3;++t)
				for(int i=0;i<3;++i)
					memcpy(b,a,siz),--b[t],--b[i],ans+=Polya(2)*n/2;
			memcpy(b,a,siz),ans+=Polya(2)*n/2;
		}
		cout<<ans/(n<<1)<<endl;
	}
	return 0;
}



posted @ 2020-01-27 12:01  谁是鸽王  阅读(218)  评论(3编辑  收藏  举报