SRM495 div2 hard

意味わかんない。階乗/2…why。
Login - TopCoder Wiki
↑に解説が書いてあるのだろうけどもう気力がマイナス。

分かったから解説してみる。
マスが5個の場合:

こんなふうに互いに交換可能なマスを一列に並べて番号をつける。
4番のところと0、1,2,3は交換できる。
だから↓

3番のところと0、1,2は交換できる。だから↓

要素が3つになった、これは3通り。
よって5×4×3=60通り

マスがn個の場合も同様に
n×(n-1)×・・・・・×3=n!÷2

#include <cstring>
#include <string>
#include <vector>

typedef long long LL;
using namespace std;


class UNIONFIND
{
	public:
	vector<int> date;
	vector<int> scale;
	UNIONFIND(int n)
	{
		for(int i=0;i<n;i++)
		{
			date.push_back(i);
			scale.push_back(1);
		}
	}
	int root(int n)
	{
		if(date[n]==n)
			return n;
		else
			return date[n]=root(date[n]);
	}
	void unionSet(int x,int y)
	{
		if(root(x)==root(y))
			return;
		scale[root(y)]+=scale[root(x)];
		scale[root(x)]=0;
		date[root(x)]=date[root(y)];
	}
	int unionSize(int n)
	{
		return scale[root(n)];
	}
};

class HexagonPuzzle
{
	public:
	
		LL MOD;

		int theCount(vector<string> board)
		{
			MOD=1000000007;
			int n=board.size();
			UNIONFIND U(n*n);

			for(int y1=0;y1<n;y1++)
				for(int x1=0;x1<=y1;x1++)
				{
					int y2=y1+1,y3=y1+1,x2=x1,x3=x1+1;
					if(0<=y2 && y2<n && 0<=x2 && x2<=y2 && 
							0<=y3 && y3<n && 0<=x3 && x3<=y3
							&& board[y1][x1]=='.' && board[y2][x2]=='.'
							&& board[y3][x3]=='.')
						U.unionSet(y1*n+x1,y2*n+x2),U.unionSet(y1*n+x1,y3*n+x3);
					y2=y1,y3=y1+1,x2=x1+1,x3=x1+1;
					if(0<=y2 && y2<n && 0<=x2 && x2<=y2 && 
							0<=y3 && y3<n && 0<=x3 && x3<=y3
							&& board[y1][x1]=='.' && board[y2][x2]=='.'
							&& board[y3][x3]=='.')
						U.unionSet(y1*n+x1,y2*n+x2),U.unionSet(y1*n+x1,y3*n+x3);
				}

			LL ans=1;
			LL fact[3000];
			fact[2]=1;
			for(LL i=3;i<3000;i++)
				fact[i]=fact[i-1]*i%MOD;
			
			//printf("here\n");
			
			for(int i=0;i<n*n;i++)
			{
				LL a=0;
				for(int j=0;j<n*n;j++)
					if(U.root(j)==i)
						a++;
				//printf("a=%d\n",a);
				if(2<a)
					ans=(ans*fact[a])%MOD;
			}
			return (int)ans;
		}
};