UVA_10601

    对于一个立方体,一共有24种本质不同的旋转,整体上分为四类:

    ①静止不动;

    ②以某面与对面的中心的连线为轴,沿一个方向旋转90度、180度、270度;

    ③以某棱与对棱的中心的连线为轴,沿一个方向旋转180度;

    ④以某个顶点与对顶点的连线为轴,沿一个方向旋转60度、120度。

    对于每类都可以用组合数计算出不动方案的种数,然后应用一下burnside引理就可以得到最后的结果了。

#include<stdio.h>
#include<string.h>
int a[6], b[6], C[15][15];
void prepare()
{
    int i, j;
    memset(C, 0, sizeof(C));
    C[0][0] = 1;
    for(i = 1; i <= 12; i ++)
    {
        C[i][0] = C[i][i] = 1;
        for(j = 1; j < i; j ++)
            C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
    }
}
void init()
{
    int i, k;
    memset(a, 0, sizeof(a));
    for(i = 0; i < 12; i ++)
    {
        scanf("%d", &k);
        ++ a[k - 1];
    }
}
long long calculate(int m)
{
    int i, j, n = 0;
    long long ans = 1;
    for(i = 0; i < 6; i ++)
    {
        if(b[i] % m != 0)
            return 0;
        b[i] /= m;
        n += b[i];
    }
    for(i = 0; i < 6; i ++)
    {
        ans *= C[n][b[i]];
        n -= b[i];
    }
    return ans;
}
long long fsolve()
{
    long long ans = 0;
    memcpy(b, a, sizeof(a));
    ans += calculate(1);
    memcpy(b, a, sizeof(a));
    ans += 6 * calculate(4);
    memcpy(b, a, sizeof(a));
    ans += 3 * calculate(2);
    return ans;
}
long long esolve()
{
    int i, j;
    long long ans = 0;
    for(i = 0; i < 6; i ++)
        for(j = 0; j < 6; j ++)
        {
            memcpy(b, a, sizeof(a));
            -- b[i], -- b[j];
            if(b[i] < 0 || b[j] < 0)
                continue;
            ans += 6 * calculate(2);
        }
    return ans;
}
long long vsolve()
{
    long long ans = 0;
    memcpy(b, a, sizeof(a));
    ans = 8 * calculate(3);
    return ans;
}
void solve()
{
    long long ans = 0;
    ans += fsolve();
    ans += esolve();
    ans += vsolve();
    printf("%lld\n", ans / 24);
}
int main()
{
    int t;
    prepare();
    scanf("%d", &t);
    while(t --)
    {
        init();
        solve();
    }
    return 0;
}