题意:用12根木条搭建正方体,给出每根木条颜色,木条颜色编号1~6,求能搭建不同的正方体的数量。两个正方体视为不同当且仅当不能在旋转翻转等操作后重合。
样例:
3
1 2 2 2 2 2 2 2 2 2 2 2
1 1 2 2 2 2 2 2 2 2 2 2
1 1 2 2 3 3 4 4 5 5 6 6
输出:
1
5
312120
分析:
置换群
。
不动置换:
绕x-x’轴旋转:
选取x-x’的方式有三种,所以以上置换形式的数目要乘三。
绕y-y’轴旋转:
选取y-y’的方式有六种,所以以上置换形式的数目要乘六。
绕z-z’轴旋转:
选取z-z’的方式有四种,所以以上置换形式的数目要乘四。
对应的多项式
:
不动置换:
绕x-x’轴旋转:
绕y-y’轴旋转:
绕z-z’轴旋转:
对于第二个样例:1 1 2 2 2 2 2 2 2 2 2 2
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 13
#define LL long long
LL fac[MAXN];
int c[MAXN],n[4]={12,3,4,6},m[4]={1,4,3,2},a[4]={1,6,8,3};
int main()
{
fac[0]=1;
for(int i=1;i<MAXN;i++)
fac[i]=fac[i-1]*i;
int tm,x;
scanf("%d",&tm);
while(tm--)
{
for(int i=1;i<=6;i++) c[i]=0;
for(int i=1;i<=12;i++)
{
scanf("%d",&x);
c[x]++;
}
LL ans=0;
for(int i=0;i<4;i++)
{
LL tmp=fac[n[i]];
for(int j=1;j<=6;j++)
if(c[j]%m[i]==0)
tmp/=fac[c[j]/m[i]];
else
{
tmp=0;
break;
}
ans+=a[i]*tmp;
}
for(int i=1;i<=6;i++)
{
if(c[i]==0) continue;
for(int j=i;j<=6;j++)
{
if(c[j]==0) continue;
if(i==j&&c[j]<2) continue;
c[i]--,c[j]--;
LL tmp=fac[6]*(1+(i!=j));
for(int k=1;k<=6;k++)
if(c[k]%2==0)
tmp/=fac[c[k]/2];
else
{
tmp=0;
break;
}
c[i]++,c[j]++;
ans+=tmp;
}
}
printf("%lld\n",ans/24);
}
}