【UVa 10601】Cubes (群论、Burnside引理、DP)

本文探讨了使用不同颜色的木棍拼接成正方体的问题,并通过动态规划与Burnside引理解决该问题。文章提供了详细的源代码及解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

给定1212根木棍的颜色(用161…6表示),求可以拼成多少个不同的正方体。

Solution

发现一共有6×4=246×4=24种置换。
fi,j,k,l,m,n,ofi,j,k,l,m,n,o表示第11种颜色有i个,第22种颜色有j的方案数。直接dp出方案数,用BurnsideBurnside引理计算即可。
我居然智障地把所有置换都打表了?!其实完全直接把置换的不变元的数量手算出来

Source Code

/**************************************
 * Au: Hany01
 * Date: Feb 2nd, 2018
 * Prob: UVa 10601 Cubes
 * Email: hany01@foxmail.com
**************************************/

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

typedef unsigned long long LL;
typedef pair<int, int> PII;
#define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fd(i, j, k) for (i = (j); i >= (k); -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define fir first
#define sec second
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define ALL(a) (a).begin(), (a).end()
#define SZ(a) ((int)(a).size())
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define debug(...) fprintf(stderr, __VA_ARGS__)

template <typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }

inline int read()
{
    register int _, __; register char c_;
    for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
    for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
    return _ * __;
}

inline void File()
{
#ifdef hany01
    freopen("uva10601.in", "r", stdin);
    freopen("uva10601.out", "w", stdout);
#endif
}

const int mp[24][12] = 
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
2, 3, 4, 1, 6, 7, 8, 5, 10, 11, 12, 9,
3, 4, 1, 2, 7, 8, 5, 6, 11, 12, 9, 10,
4, 1, 2, 3, 8, 5, 6, 7, 12, 9, 10, 11,
9, 6, 1, 5, 12, 10, 2, 4, 11, 7, 3, 8,
6, 1, 5, 9, 10, 2, 4, 12, 7, 3, 8, 11,
1, 5, 9, 6, 2, 4, 12, 10, 3, 8, 11, 7,
5, 9, 6, 1, 4, 12, 10, 2, 8, 11, 7, 3,
2, 6, 10, 7, 3, 1, 9, 11, 4, 5, 12, 8,
6, 10, 7, 2, 1, 9, 11, 3, 5, 12, 8, 4,
10, 7, 2, 6, 9, 11, 3, 1, 12, 8, 4, 5,
7, 2, 6, 10, 11, 3, 1, 9, 8, 4, 5, 12,
3, 7, 11, 8, 4, 2, 10, 12, 1, 6, 9, 5,
7, 11, 8, 3, 2, 10, 12, 4, 6, 9, 5, 1,
11, 8, 3, 7, 10, 12, 4, 2, 9, 5, 1, 6,
8, 3, 7, 11, 12, 4, 2, 10, 5, 1, 6, 9,
4, 8, 12, 5, 1, 3, 11, 9, 2, 7, 10, 6,
8, 12, 5, 4, 3, 11, 9, 1, 7, 10, 6, 2,
12, 5, 4, 8, 11, 9, 1, 3, 10, 6, 2, 7,
5, 4, 8, 12, 9, 1, 3, 11, 6, 2, 7, 10,
12, 11, 10, 9, 5, 8, 7, 6, 4, 3, 2, 1,
11, 10, 9, 12, 8, 7, 6, 5, 3, 2, 1, 4,
10, 9, 12, 11, 7, 6, 5, 8, 2, 1, 4, 3,
9, 12, 11, 10, 6, 5, 8, 7, 1, 4, 3, 2,
};
const int maxn = 14, maxc = 7;

LL Ans;
int f[maxn][maxn][maxn][maxn][maxn][maxn], o[maxc], co[maxc], t, vis[maxn], R[maxn], cnt;

inline LL Pow(LL a, LL b) {
    LL Ans = 1;
    for ( ; b; b >>= 1, a = a * a) if (b & 1) Ans *= a;
    return Ans;
}

inline void DP()
{
    int o[7];
    Set(f, 0), f[0][0][0][0][0][0] = 1;
    For(cur, 1, cnt)
        Fd(o[1], co[1], 0) Fd(o[2], co[2], 0) Fd(o[3], co[3], 0)
            Fd(o[4], co[4], 0) Fd(o[5], co[5], 0) Fd(o[6], co[6], 0) {
                if (o[1] >= R[cur]) f[o[1]][o[2]][o[3]][o[4]][o[5]][o[6]] += f[o[1] - R[cur]][o[2]][o[3]][o[4]][o[5]][o[6]];
                if (o[2] >= R[cur]) f[o[1]][o[2]][o[3]][o[4]][o[5]][o[6]] += f[o[1]][o[2] - R[cur]][o[3]][o[4]][o[5]][o[6]];
                if (o[3] >= R[cur]) f[o[1]][o[2]][o[3]][o[4]][o[5]][o[6]] += f[o[1]][o[2]][o[3] - R[cur]][o[4]][o[5]][o[6]];
                if (o[4] >= R[cur]) f[o[1]][o[2]][o[3]][o[4]][o[5]][o[6]] += f[o[1]][o[2]][o[3]][o[4] - R[cur]][o[5]][o[6]];
                if (o[5] >= R[cur]) f[o[1]][o[2]][o[3]][o[4]][o[5]][o[6]] += f[o[1]][o[2]][o[3]][o[4]][o[5] - R[cur]][o[6]];
                if (o[6] >= R[cur]) f[o[1]][o[2]][o[3]][o[4]][o[5]][o[6]] += f[o[1]][o[2]][o[3]][o[4]][o[5]][o[6] - R[cur]];
            }
    Ans += f[co[1]][co[2]][co[3]][co[4]][co[5]][co[6]];
}

int main()
{
    File();
    for (register int T = read(); T --; ) {
        Set(co, 0), Ans = 0;
        For(i, 1, 12) ++ co[read()];
        rep(cur, 24) {
            cnt = 0, Set(vis, 0);
            rep(i, 12) if (!vis[t = i]) {
                ++ cnt, R[cnt] = 0;
                while (!vis[t]) vis[t] = 1, t = mp[cur][t] - 1, ++ R[cnt];
            }
            DP();
        }
        Ans /= 24;
        cout << Ans << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值