arc062 E - Building Cubes with AtCoDeer

E - Building Cubes with AtCoDeer

计数题,首先当前砖块的情况可以压缩成1个long long表示,考虑处理出每个砖块旋转同构的所有情况中,压缩后数字最小的那个作为该砖块权值。

然后枚举顶面与下底面i,j (i < j),然后枚举下底面相对顶面的旋转情况,再考察插入四周四个面,注意四周面可能是四色相同或者对角相同,需要额外统计。

这样显然一种可行方案被统计3次,最后答案除以3即可。

#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define sc second
#define pb push_back
#define ll long long
#define trav(v,x) for(auto v:x)
#define all(x) (x).begin(), (x).end()
#define VI vector<int>
#define VLL vector<ll>
#define pll pair<ll, ll>
#define double long double
//#define int long long
using namespace std;
const int N = 1e6 + 100;
const int inf = 1e9;
//const ll inf = 1e18;

#ifdef LOCAL
void debug_out(){cerr << endl;}
template<typename Head, typename... Tail>
void debug_out(Head H, Tail... T)
{
	cerr << " " << to_string(H);
	debug_out(T...);
}
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

#define node array<int, 4>

map<ll, ll> cnt;

ll cal_val(node x)
{
	ll nw = 0;
	for(int i = 0; i < 4; i++)
	{
		nw = nw * 1000LL + x[i];
	}
	return nw;
}

node rot(node x)
{
	node y;
	for(int i = 0; i < 4; i++)
		y[i] = x[(i + 1) % 4];
	return y;
}

ll cal_id(node x)
{
	ll mn = 1e18;
	for(int i = 0; i < 4; i++)
	{
		ll nw = cal_val(x);
		mn = min(mn, nw);
		x = rot(x);
	}
	return mn; 
}

void add(node x, int y)
{
	ll id = cal_id(x);
	cnt[id] += y;
}

ll ffac(ll x, int y)
{
	ll res = 1;
	for(ll i = 0; i < y; i++)
		res = res * (x - i);
	return res;
}

void sol()
{
	int n;
	cin >> n;
	vector<node> a(n);
	for(int i = 0; i < n; i++)
	{
		int x, y, z, t;
		cin >> x >> y >> z >> t;
		a[i] = {x, y, z, t};
		add(a[i], 1);
	}
	ll ans = 0;
	for(int i = 0; i < n; i++)
	{
		//cerr << "!!!!!" << i << ' ' << cnt[cal_id(a[i])] << '\n';
		add(a[i], -1);
		for(int r = 0; r < 4; r++)
		{
			for(int j = i + 1; j < n; j++)
			{
				map<ll, int> need;
				add(a[j], -1);
				swap(a[j][1], a[j][3]);
				ll res = 1;
				for(int face = 0; face < 4; face++)
				{
					//cerr << i << ' ' << r << ' ' << j << ' ' << face << '\n';
					node nw;
					nw[0] = a[i][face];
					nw[1] = a[i][(face + 3) % 4];
					nw[2] = a[j][(face + 3) % 4];
					nw[3] = a[j][face];
//					cerr << nw[0] << ' ' << nw[1] << ' '  << nw[2] << ' ' << nw[3] << '\n';
//					system("pause");
					if(nw[0] == nw[1] && nw[1] == nw[2] && nw[2] == nw[3])
						res = res * 4;
					else if(nw[0] == nw[2] && nw[1] == nw[3])
						res = res * 2;
					need[cal_id(nw)]++;	
				}
				trav(v, need)
				{
					res = res * ffac(cnt[v.fi], v.sc);
				}
				ans = (ans + res);
				swap(a[j][1], a[j][3]);
				add(a[j], 1);
			}
			a[i] = rot(a[i]);	
		}
		add(a[i], 1);
		//cerr << "!!!??" << i << ' ' << cnt[cal_id(a[i])] << '\n';
	}
	cout << ans / 3 << '\n';
}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
//	int tt;
//	cin >> tt;
//	while(tt--)
		sol();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值